use crate::{context::CommandContext, modifier::RedirectModifier, tree::CommandNode}; use super::{literal_argument_builder::Literal, required_argument_builder::Argument}; use std::{any::Any, cell::RefCell, collections::BTreeMap, fmt::Debug, rc::Rc}; #[derive(Debug, Clone)] pub enum ArgumentBuilderType { Literal(Literal), Argument(Argument), } /// A node that hasn't yet been built. #[derive(Clone)] pub struct ArgumentBuilder { arguments: CommandNode, command: Option) -> i32>>, requirement: Rc) -> bool>, target: Option>>>, forks: bool, modifier: Option>>, } /// A node that isn't yet built. impl ArgumentBuilder { pub fn new(value: ArgumentBuilderType) -> Self { Self { arguments: CommandNode { value, ..Default::default() }, command: None, requirement: Rc::new(|_| true), forks: false, modifier: None, target: None, } } pub fn then(&mut self, argument: ArgumentBuilder) -> Self { self.arguments .add_child(&Rc::new(RefCell::new(argument.build()))); self.clone() } pub fn executes(&mut self, f: F) -> Self where F: Fn(&CommandContext) -> i32 + 'static, { self.command = Some(Rc::new(f)); self.clone() } pub fn requires(&mut self, requirement: F) -> Self where F: Fn(Rc) -> bool + 'static, { self.requirement = Rc::new(requirement); self.clone() } pub fn redirect(&mut self, target: Rc>>) -> Self { self.forward(target, None, false) } pub fn forward( &mut self, target: Rc>>, modifier: Option>>, fork: bool, ) -> Self { if !self.arguments.children.is_empty() { panic!("Cannot forward a node with children"); } self.target = Some(target); self.modifier = modifier; self.forks = fork; self.clone() } pub fn build(self) -> CommandNode { let mut result = CommandNode { value: self.arguments.value, command: self.command.clone(), requirement: self.requirement.clone(), redirect: self.target.clone(), modifier: self.modifier.clone(), forks: self.forks, ..Default::default() }; for (_, argument) in &self.arguments.children { result.add_child(argument); } result } } impl Debug for ArgumentBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ArgumentBuilder") .field("arguments", &self.arguments) // .field("command", &self.command) // .field("requirement", &self.requirement) .field("target", &self.target) .field("forks", &self.forks) // .field("modifier", &self.modifier) .finish() } } #[cfg(test)] mod tests { use std::rc::Rc; use crate::{ builder::{literal_argument_builder::literal, required_argument_builder::argument}, parsers::integer, }; use super::ArgumentBuilder; // public class ArgumentBuilderTest { // private TestableArgumentBuilder builder; // @Before // public void setUp() throws Exception { // builder = new TestableArgumentBuilder<>(); // } // @Test // public void testArguments() throws Exception { // final RequiredArgumentBuilder argument = argument("bar", integer()); // builder.then(argument); // assertThat(builder.getArguments(), hasSize(1)); // assertThat(builder.getArguments(), hasItem((CommandNode) argument.build())); // } #[test] fn test_arguments() { let mut builder: ArgumentBuilder<()> = literal("foo"); let argument: ArgumentBuilder<()> = argument("bar", integer()); builder.then(argument.clone()); assert_eq!(builder.arguments.children.len(), 1); let built_argument = Rc::new(argument.build()); assert!(builder .arguments .children .values() .any(|e| *e.borrow() == *built_argument)); } // @Test // public void testRedirect() throws Exception { // final CommandNode target = mock(CommandNode.class); // builder.redirect(target); // assertThat(builder.getRedirect(), is(target)); // } // @Test(expected = IllegalStateException.class) // public void testRedirect_withChild() throws Exception { // final CommandNode target = mock(CommandNode.class); // builder.then(literal("foo")); // builder.redirect(target); // } // @Test(expected = IllegalStateException.class) // public void testThen_withRedirect() throws Exception { // final CommandNode target = mock(CommandNode.class); // builder.redirect(target); // builder.then(literal("foo")); // } // private static class TestableArgumentBuilder extends ArgumentBuilder> { // @Override // protected TestableArgumentBuilder getThis() { // return this; // } // @Override // public CommandNode build() { // return null; // } // } // } }