diff options
Diffstat (limited to 'azalea-brigadier/src/tree/command_node.rs')
| -rw-r--r-- | azalea-brigadier/src/tree/command_node.rs | 119 |
1 files changed, 108 insertions, 11 deletions
diff --git a/azalea-brigadier/src/tree/command_node.rs b/azalea-brigadier/src/tree/command_node.rs index b8f416eb..f59b1cef 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -1,4 +1,7 @@ -use super::{argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode}; +use super::{ + argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode, + root_command_node::RootCommandNode, +}; use crate::{ arguments::argument_type::ArgumentType, builder::argument_builder::ArgumentBuilder, @@ -12,19 +15,98 @@ use crate::{ use dyn_clonable::*; use std::{any::Any, collections::HashMap, fmt::Debug}; -#[derive(Default)] pub struct BaseCommandNode<'a, S> { - children: HashMap<String, &'a dyn CommandNode<S>>, + children: HashMap<String, Box<dyn CommandNode<S>>>, literals: HashMap<String, LiteralCommandNode<'a, S>>, arguments: HashMap<String, ArgumentCommandNode<'a, S>>, - requirement: Option<&'a dyn Fn(&S) -> bool>, - redirect: Option<&'a dyn CommandNode<S>>, - modifier: Option<&'a dyn RedirectModifier<S>>, + requirement: Box<dyn Fn(&S) -> bool>, + redirect: Option<Box<dyn CommandNode<S>>>, + modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, - command: Option<&'a dyn Command<S>>, + command: Option<Box<dyn Command<S>>>, } -impl<S> BaseCommandNode<'_, S> {} +impl<S> BaseCommandNode<'_, S> { + pub fn command(&self) -> &Option<Box<dyn Command<S>>> { + &self.command + } + + pub fn children(&self) -> &HashMap<String, Box<dyn CommandNode<S>>> { + &self.children + } + + pub fn child(&self, name: &str) -> Option<&dyn CommandNode<S>> { + self.children.get(name).map(|child| child.as_ref()) + } + + pub fn redirect(&self) -> Option<&dyn CommandNode<S>> { + self.redirect.as_ref().map(|redirect| redirect.as_ref()) + } + + pub fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> { + self.modifier.as_ref().map(|modifier| modifier.as_ref()) + } + + pub fn can_use(&self, source: S) -> bool { + (self.requirement)(&source) + } + + // public void addChild(final CommandNode<S> node) { + // if (node instanceof RootCommandNode) { + // throw new UnsupportedOperationException("Cannot add a RootCommandNode as a child to any other CommandNode"); + // } + + // final CommandNode<S> child = children.get(node.getName()); + // if (child != null) { + // // We've found something to merge onto + // if (node.getCommand() != null) { + // child.command = node.getCommand(); + // } + // for (final CommandNode<S> grandchild : node.getChildren()) { + // child.addChild(grandchild); + // } + // } else { + // children.put(node.getName(), node); + // if (node instanceof LiteralCommandNode) { + // literals.put(node.getName(), (LiteralCommandNode<S>) node); + // } else if (node instanceof ArgumentCommandNode) { + // arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node); + // } + // } + // } + + pub fn add_child(&self, node: &dyn CommandNode<S>) -> Result<(), String> { + if (&node as &dyn Any).is::<RootCommandNode<S>>() { + return Err(String::from( + "Cannot add a RootCommandNode as a child to any other CommandNode", + )); + } + + let child = self.children.get(node.name()); + if let Some(child) = child { + // We've found something to merge onto + if let Some(command) = node.base.command() { + child.command = Some(command); + } + for grandchild in node.children() { + child.add_child(grandchild)?; + } + } else { + self.children.insert(node.name().to_string(), node); + if let Some(literal) = + &node.clone_boxed() as &dyn Any as &dyn Any as &LiteralCommandNode<S> + { + self.literals + .insert(node.name().to_string(), literal.clone_boxed()); + } else if let Some(argument) = + &node.clone_boxed() as &dyn Any as &dyn Any as &ArgumentCommandNode<S> + { + self.arguments + .insert(node.name().to_string(), argument.clone_boxed()); + } + } + } +} impl<S> Clone for BaseCommandNode<'_, S> { fn clone(&self) -> Self { @@ -56,8 +138,22 @@ impl<S> Debug for BaseCommandNode<'_, S> { } } -#[clonable] -pub trait CommandNode<S>: Clone { +impl<S> Default for BaseCommandNode<'_, S> { + fn default() -> Self { + Self { + children: HashMap::new(), + literals: HashMap::new(), + arguments: HashMap::new(), + requirement: Box::new(|_| true), + redirect: None, + modifier: None, + forks: false, + command: None, + } + } +} + +pub trait CommandNode<S> { fn name(&self) -> &str; fn usage_text(&self) -> &str; fn parse( @@ -68,9 +164,10 @@ pub trait CommandNode<S>: Clone { fn list_suggestions( &self, context: CommandContext<S>, - builder: SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException>; fn is_valid_input(&self, input: &str) -> bool; fn create_builder(&self) -> dyn ArgumentBuilder<S, dyn Any>; fn get_examples(&self) -> Vec<String>; + fn base(&self) -> &BaseCommandNode<S>; } |
