aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src/builder/argument_builder.rs
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-17 14:02:13 -0500
committermat <github@matdoes.dev>2022-04-17 14:02:13 -0500
commita72a47ced76065caf739898954cd18edbc39174b (patch)
tree5526c7663f253bbd7c8318b9d98413f1f2074852 /azalea-brigadier/src/builder/argument_builder.rs
parent4ff67d4917ce333232189e86aee09f2d82451fc6 (diff)
downloadazalea-drasl-a72a47ced76065caf739898954cd18edbc39174b.tar.xz
Rewrite brigadier
Diffstat (limited to 'azalea-brigadier/src/builder/argument_builder.rs')
-rw-r--r--azalea-brigadier/src/builder/argument_builder.rs257
1 files changed, 149 insertions, 108 deletions
diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs
index d0770be2..1fb775c2 100644
--- a/azalea-brigadier/src/builder/argument_builder.rs
+++ b/azalea-brigadier/src/builder/argument_builder.rs
@@ -1,137 +1,178 @@
-use crate::{
- arguments::argument_type::ArgumentType,
- command::Command,
- redirect_modifier::RedirectModifier,
- single_redirect_modifier::SingleRedirectModifier,
- tree::{
- command_node::{BaseCommandNode, CommandNodeTrait},
- root_command_node::RootCommandNode,
- },
-};
-use std::fmt::Debug;
-
-pub struct BaseArgumentBuilder<'a, S> {
- arguments: RootCommandNode<'a, S>,
- command: Option<Box<dyn Command<S>>>,
- requirement: Box<dyn Fn(&S) -> bool>,
- target: Option<Box<dyn CommandNodeTrait<S>>>,
- modifier: Option<Box<dyn RedirectModifier<S>>>,
- forks: bool,
+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),
}
-pub trait ArgumentBuilder<S> {
- fn build(self) -> Box<dyn CommandNodeTrait<S>>;
+/// A node that hasn't yet been built.
+#[derive(Clone)]
+pub struct ArgumentBuilder<S: Any + Clone> {
+ value: ArgumentBuilderType,
+
+ children: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>,
+ literals: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>,
+ arguments: BTreeMap<String, Rc<RefCell<CommandNode<S>>>>,
+
+ executes: Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>,
+ requirement: Rc<dyn Fn(Rc<S>) -> bool>,
+ forks: bool,
+ modifier: Option<Rc<dyn RedirectModifier<S>>>,
}
-impl<'a, S> BaseArgumentBuilder<'a, S> {
- pub fn then(&mut self, argument: Box<dyn ArgumentBuilder<S>>) -> Result<&mut Self, String> {
- if self.target.is_some() {
- return Err("Cannot add children to a redirected node".to_string());
- }
- self.arguments.add_child(argument.build());
- Ok(self)
- }
+// todo: maybe remake this to be based on a CommandNode like vanilla does?
- pub fn arguments(&self) -> &Vec<&dyn CommandNodeTrait<S>> {
- &self.arguments.get_children()
+/// A node that isn't yet built.
+impl<S: Any + Clone> ArgumentBuilder<S> {
+ pub fn new(value: ArgumentBuilderType) -> Self {
+ Self {
+ value,
+ children: BTreeMap::new(),
+ literals: BTreeMap::new(),
+ arguments: BTreeMap::new(),
+ executes: None,
+ requirement: Rc::new(|_| true),
+ forks: false,
+ modifier: None,
+ }
}
- pub fn executes(&mut self, command: Box<dyn Command<S>>) -> &mut Self {
- self.command = Some(command);
+ pub fn then(&mut self, node: ArgumentBuilder<S>) -> &mut Self {
+ let built_node = node.build();
+ let name = built_node.name();
+ let node_reference = Rc::new(RefCell::new(built_node.clone()));
+ self.children
+ .insert(name.to_string(), node_reference.clone());
+ match &built_node.value {
+ ArgumentBuilderType::Literal(literal) => {
+ self.literals.insert(name.to_string(), node_reference);
+ }
+ ArgumentBuilderType::Argument(argument) => {
+ self.arguments.insert(name.to_string(), node_reference);
+ }
+ }
self
}
- pub fn command(&self) -> Option<Box<dyn Command<S>>> {
- self.command
+ pub fn executes<F>(&mut self, f: F) -> Self
+ where
+ F: Fn(&CommandContext<S>) -> i32 + 'static,
+ {
+ self.executes = Some(Rc::new(f));
+ self.clone()
}
- pub fn requires(&mut self, requirement: Box<dyn Fn(&S) -> bool>) -> &mut Self {
- self.requirement = requirement;
- self
- }
+ pub fn build(self) -> CommandNode<S> {
+ println!("building {:?}", self);
+ CommandNode {
+ value: self.value,
- pub fn requirement(&self) -> Box<dyn Fn(&S) -> bool> {
- self.requirement
- }
+ children: self.children,
+ literals: self.literals,
+ arguments: self.arguments,
- pub fn redirect(&mut self, target: Box<dyn CommandNodeTrait<S>>) -> &mut Self {
- self.forward(target, None, false)
+ command: self.executes.clone(),
+ requirement: self.requirement.clone(),
+ redirect: None,
+ forks: self.forks,
+ modifier: self.modifier,
+ }
}
+}
- pub fn redirect_modifier(
- &mut self,
- target: &dyn CommandNodeTrait<S>,
- modifier: &dyn SingleRedirectModifier<S>,
- ) -> &mut Self {
- // forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false);
- self.forward(target, modifier.map(|m| |o| vec![m.apply(o)]), false)
+impl<S: Any + Clone> Debug for ArgumentBuilder<S> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("ArgumentBuilder")
+ .field("value", &self.value)
+ .field("children", &self.children)
+ .field("literals", &self.literals)
+ .field("arguments", &self.arguments)
+ .field("executes", &self.executes.is_some())
+ // .field("requirement", &self.requirement)
+ .field("forks", &self.forks)
+ // .field("modifier", &self.modifier)
+ .finish()
}
+}
- pub fn fork(
- &mut self,
- target: &dyn CommandNodeTrait<S>,
- modifier: &dyn RedirectModifier<S>,
- ) -> &mut Self {
- self.forward(target, Some(modifier), true)
- }
+#[cfg(test)]
+mod tests {
+ use std::rc::Rc;
- pub fn forward(
- &mut self,
- target: Option<Box<dyn CommandNodeTrait<S>>>,
- modifier: Option<&dyn RedirectModifier<S>>,
- fork: bool,
- ) -> Result<&mut Self, String> {
- if !self.arguments.get_children().is_empty() {
- return Err("Cannot forward a node with children".to_string());
- }
- self.target = target;
- self.modifier = modifier;
- self.forks = fork;
- Ok(self)
- }
+ use crate::{
+ builder::{literal_argument_builder::literal, required_argument_builder::argument},
+ parsers::integer,
+ };
- pub fn get_redirect(&self) -> Option<&dyn CommandNodeTrait<S>> {
- self.target.as_ref()
- }
+ use super::ArgumentBuilder;
- pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> {
- self.modifier.as_ref()
- }
+ // public class ArgumentBuilderTest {
+ // private TestableArgumentBuilder<Object> builder;
- pub fn is_fork(&self) -> bool {
- self.forks
- }
+ // @Before
+ // public void setUp() throws Exception {
+ // builder = new TestableArgumentBuilder<>();
+ // }
- pub fn build(self) -> BaseCommandNode<'a, S> {
- let result: BaseCommandNode<'a, S> = BaseCommandNode {
- command: self.command,
- requirement: self.requirement,
- redirect: self.target,
- modifier: self.modifier,
- forks: self.forks,
+ // @Test
+ // public void testArguments() throws Exception {
+ // final RequiredArgumentBuilder<Object, ?> argument = argument("bar", integer());
- arguments: Default::default(),
- children: Default::default(),
- literals: Default::default(),
- };
+ // builder.then(argument);
- for argument in self.arguments() {
- result.add_child(argument);
- }
+ // assertThat(builder.getArguments(), hasSize(1));
+ // assertThat(builder.getArguments(), hasItem((CommandNode<Object>) argument.build()));
+ // }
- result
- }
-}
+ #[test]
+ fn test_arguments() {
+ let mut builder: ArgumentBuilder<()> = literal("foo");
-impl<S> Default for BaseArgumentBuilder<'_, S> {
- fn default() -> Self {
- Self {
- arguments: Default::default(),
- command: Default::default(),
- requirement: Default::default(),
- target: Default::default(),
- modifier: Default::default(),
- forks: Default::default(),
- }
+ let argument: ArgumentBuilder<()> = argument("bar", integer());
+ builder.then(argument.clone());
+ assert_eq!(builder.children.len(), 1);
+ let built_argument = Rc::new(argument.build());
+ assert!(builder
+ .children
+ .values()
+ .any(|e| *e.borrow() == *built_argument));
}
+
+ // @Test
+ // public void testRedirect() throws Exception {
+ // final CommandNode<Object> target = mock(CommandNode.class);
+ // builder.redirect(target);
+ // assertThat(builder.getRedirect(), is(target));
+ // }
+
+ // @Test(expected = IllegalStateException.class)
+ // public void testRedirect_withChild() throws Exception {
+ // final CommandNode<Object> target = mock(CommandNode.class);
+ // builder.then(literal("foo"));
+ // builder.redirect(target);
+ // }
+
+ // @Test(expected = IllegalStateException.class)
+ // public void testThen_withRedirect() throws Exception {
+ // final CommandNode<Object> target = mock(CommandNode.class);
+ // builder.redirect(target);
+ // builder.then(literal("foo"));
+ // }
+
+ // private static class TestableArgumentBuilder<S> extends ArgumentBuilder<S, TestableArgumentBuilder<S>> {
+ // @Override
+ // protected TestableArgumentBuilder<S> getThis() {
+ // return this;
+ // }
+
+ // @Override
+ // public CommandNode<S> build() {
+ // return null;
+ // }
+ // }
+ // }
}