diff options
| -rw-r--r-- | azalea-brigadier/src/builder/argument_builder.rs | 37 | ||||
| -rw-r--r-- | azalea-brigadier/src/builder/literal_argument_builder.rs | 29 | ||||
| -rw-r--r-- | azalea-brigadier/src/builder/required_argument_builder.rs | 35 | ||||
| -rw-r--r-- | azalea-brigadier/src/command_dispatcher.rs | 1 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/command_context.rs | 4 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/command_context_builder.rs | 21 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/parsed_command_node.rs | 8 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/suggestion_context.rs | 4 | ||||
| -rw-r--r-- | azalea-brigadier/src/string_reader.rs | 14 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/argument_command_node.rs | 67 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/command_node.rs | 152 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/literal_command_node.rs | 61 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/root_command_node.rs | 31 |
13 files changed, 272 insertions, 192 deletions
diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index ec2756ca..d0770be2 100644 --- a/azalea-brigadier/src/builder/argument_builder.rs +++ b/azalea-brigadier/src/builder/argument_builder.rs @@ -4,40 +4,35 @@ use crate::{ redirect_modifier::RedirectModifier, single_redirect_modifier::SingleRedirectModifier, tree::{ - command_node::{BaseCommandNode, CommandNode}, + command_node::{BaseCommandNode, CommandNodeTrait}, root_command_node::RootCommandNode, }, }; +use std::fmt::Debug; -pub struct BaseArgumentBuilder<'a, S> -where - S: Sized, -{ +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 CommandNode<S>>>, + target: Option<Box<dyn CommandNodeTrait<S>>>, modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, } -pub trait ArgumentBuilder<S, T> -where - T: ArgumentBuilder<S, T>, -{ - fn build(self) -> Box<dyn CommandNode<S>>; +pub trait ArgumentBuilder<S> { + fn build(self) -> Box<dyn CommandNodeTrait<S>>; } impl<'a, S> BaseArgumentBuilder<'a, S> { - pub fn then(&mut self, argument: Box<dyn CommandNode<S>>) -> Result<&mut Self, String> { + 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) } - pub fn arguments(&self) -> &Vec<&dyn CommandNode<S>> { + pub fn arguments(&self) -> &Vec<&dyn CommandNodeTrait<S>> { &self.arguments.get_children() } @@ -59,13 +54,13 @@ impl<'a, S> BaseArgumentBuilder<'a, S> { self.requirement } - pub fn redirect(&mut self, target: Box<dyn CommandNode<S>>) -> &mut Self { + pub fn redirect(&mut self, target: Box<dyn CommandNodeTrait<S>>) -> &mut Self { self.forward(target, None, false) } pub fn redirect_modifier( &mut self, - target: &dyn CommandNode<S>, + target: &dyn CommandNodeTrait<S>, modifier: &dyn SingleRedirectModifier<S>, ) -> &mut Self { // forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false); @@ -74,7 +69,7 @@ impl<'a, S> BaseArgumentBuilder<'a, S> { pub fn fork( &mut self, - target: &dyn CommandNode<S>, + target: &dyn CommandNodeTrait<S>, modifier: &dyn RedirectModifier<S>, ) -> &mut Self { self.forward(target, Some(modifier), true) @@ -82,20 +77,20 @@ impl<'a, S> BaseArgumentBuilder<'a, S> { pub fn forward( &mut self, - target: Box<dyn CommandNode<S>>, - modifier: Option<Box<dyn RedirectModifier<S>>>, + 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 = Some(target); + self.target = target; self.modifier = modifier; self.forks = fork; Ok(self) } - pub fn get_redirect(&self) -> Option<&dyn CommandNode<S>> { + pub fn get_redirect(&self) -> Option<&dyn CommandNodeTrait<S>> { self.target.as_ref() } diff --git a/azalea-brigadier/src/builder/literal_argument_builder.rs b/azalea-brigadier/src/builder/literal_argument_builder.rs index 5bceb6eb..8250d45d 100644 --- a/azalea-brigadier/src/builder/literal_argument_builder.rs +++ b/azalea-brigadier/src/builder/literal_argument_builder.rs @@ -4,27 +4,38 @@ use crate::{ command::Command, redirect_modifier::RedirectModifier, tree::{ - command_node::CommandNode, literal_command_node::LiteralCommandNode, + command_node::CommandNodeTrait, literal_command_node::LiteralCommandNode, root_command_node::RootCommandNode, }, }; +use std::fmt::Debug; -pub struct LiteralArgumentBuilder<'a, S> { +pub struct LiteralArgumentBuilder<'a, S> +where + , +{ arguments: RootCommandNode<'a, S>, command: Option<Box<dyn Command<S>>>, requirement: Box<dyn Fn(&S) -> bool>, - target: Option<Box<dyn CommandNode<S>>>, + target: Option<Box<dyn CommandNodeTrait<S>>>, modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, - literal: String, } -impl<'a, S> LiteralArgumentBuilder<'a, S> { +impl<'a, S> LiteralArgumentBuilder<'a, S> +where + , +{ pub fn new(literal: String) -> Self { Self { literal, - base: BaseArgumentBuilder::default(), + arguments: RootCommandNode::new(), + command: None, + requirement: Box::new(|_| true), + target: None, + modifier: None, + forks: false, } } @@ -33,11 +44,11 @@ impl<'a, S> LiteralArgumentBuilder<'a, S> { } } -impl<'a, S, T> ArgumentBuilder<S, T> for LiteralArgumentBuilder<'a, S> +impl<'a, S> ArgumentBuilder<S> for LiteralArgumentBuilder<'a, S> where - T: ArgumentBuilder<S, T>, + , { - fn build(self) -> Box<dyn CommandNode<S>> { + fn build(self) -> Box<dyn CommandNodeTrait<S>> { let result = LiteralCommandNode::new(self.literal, self.base.build()); for argument in self.base.arguments() { diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index b577f3ed..fe6f2ecc 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -1,17 +1,23 @@ +use super::argument_builder::BaseArgumentBuilder; use crate::{ arguments::argument_type::ArgumentType, + command::Command, + redirect_modifier::RedirectModifier, suggestion::suggestion_provider::SuggestionProvider, - tree::{argument_command_node::ArgumentCommandNode, command_node::BaseCommandNode}, + tree::{ + argument_command_node::ArgumentCommandNode, + command_node::{BaseCommandNode, CommandNodeTrait}, + root_command_node::RootCommandNode, + }, }; use std::any::Any; - -use super::argument_builder::BaseArgumentBuilder; +use std::fmt::Debug; pub struct RequiredArgumentBuilder<'a, S> { arguments: RootCommandNode<'a, S>, command: Option<Box<dyn Command<S>>>, requirement: Box<dyn Fn(&S) -> bool>, - target: Option<Box<dyn CommandNode<S>>>, + target: Option<Box<dyn CommandNodeTrait<S>>>, modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, @@ -26,7 +32,12 @@ impl<'a, S> RequiredArgumentBuilder<'a, S> { name, type_: type_, suggestions_provider: None, - base: BaseArgumentBuilder::default(), + arguments: RootCommandNode::new(), + command: None, + requirement: Box::new(|_| true), + target: None, + modifier: None, + forks: false, } } @@ -62,15 +73,13 @@ impl<'a, S> RequiredArgumentBuilder<'a, S> { let result = ArgumentCommandNode { name: self.name, type_: self.type_, - base: BaseCommandNode { - command: self.base.command(), - requirement: self.base.requirement(), - redirect: self.base.get_redirect(), - modifier: self.base.get_redirect_modifier(), - forks: self.base.forks, - ..BaseCommandNode::default() - }, + command: self.base.command(), + requirement: self.base.requirement(), + redirect: self.base.get_redirect(), + modifier: self.base.get_redirect_modifier(), + forks: self.base.forks, custom_suggestions: self.base.custom_suggestions, + ..ArgumentCommandNode::default() }; for argument in self.base.arguments() { diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs index 72a353ad..98288a48 100644 --- a/azalea-brigadier/src/command_dispatcher.rs +++ b/azalea-brigadier/src/command_dispatcher.rs @@ -1,4 +1,5 @@ use crate::{arguments::argument_type::ArgumentType, tree::root_command_node::RootCommandNode}; +use std::fmt::Debug; /// The core command dispatcher, for registering, parsing, and executing commands. /// The `S` generic is a custom "source" type, such as a user or originator of a command diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index 4f0b4d49..8db1487f 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{ arguments::argument_type::ArgumentType, command::Command, redirect_modifier::RedirectModifier, - tree::command_node::CommandNode, + tree::command_node::CommandNodeTrait, }; use std::{any::Any, collections::HashMap}; @@ -13,7 +13,7 @@ pub struct CommandContext<'a, S> { input: String, command: &'a dyn Command<S>, arguments: HashMap<String, ParsedArgument<Box<dyn Any>>>, - root_node: &'a dyn CommandNode<S>, + root_node: &'a dyn CommandNodeTrait<S>, nodes: Vec<ParsedCommandNode<S>>, range: StringRange, child: Option<&'a CommandContext<'a, S>>, diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index 95da4064..969f9cfd 100644 --- a/azalea-brigadier/src/context/command_context_builder.rs +++ b/azalea-brigadier/src/context/command_context_builder.rs @@ -1,10 +1,10 @@ -use std::{any::Any, collections::HashMap}; - use crate::{ arguments::argument_type::ArgumentType, command::Command, command_dispatcher::CommandDispatcher, redirect_modifier::RedirectModifier, - tree::command_node::CommandNode, + tree::command_node::CommandNodeTrait, }; +use std::fmt::Debug; +use std::{any::Any, collections::HashMap}; use super::{ command_context::CommandContext, parsed_argument::ParsedArgument, @@ -27,12 +27,12 @@ use super::{ #[derive(Clone)] pub struct CommandContextBuilder<'a, S> { arguments: HashMap<String, ParsedArgument<Box<dyn Any>>>, - root_node: &'a dyn CommandNode<S>, + root_node: &'a dyn CommandNodeTrait<S>, nodes: Vec<ParsedCommandNode<S>>, dispatcher: CommandDispatcher<'a, S>, source: S, command: Box<dyn Command<S>>, - child: Option<CommandContextBuilder<'a, S>>, + child: Box<Option<CommandContextBuilder<'a, S>>>, range: StringRange, modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, @@ -45,11 +45,14 @@ pub struct CommandContextBuilder<'a, S> { // this.range = StringRange.at(start); // } -impl<S> CommandContextBuilder<'_, S> { +impl<S> CommandContextBuilder<'_, S> +where + , +{ pub fn new( dispatcher: CommandDispatcher<S>, source: S, - root_node: dyn CommandNode<S>, + root_node: dyn CommandNodeTrait<S>, start: usize, ) -> Self { Self { @@ -70,7 +73,7 @@ impl<S> CommandContextBuilder<'_, S> { &self.source } - pub fn root_node(&self) -> &dyn CommandNode<S> { + pub fn root_node(&self) -> &dyn CommandNodeTrait<S> { &self.root_node } @@ -88,7 +91,7 @@ impl<S> CommandContextBuilder<'_, S> { self } - pub fn with_node(mut self, node: dyn CommandNode<S>, range: StringRange) -> Self { + pub fn with_node(mut self, node: dyn CommandNodeTrait<S>, range: StringRange) -> Self { self.nodes.push(ParsedCommandNode::new(node, range)); self.range = StringRange::encompassing(&self.range, &range); self.modifier = node.redirect_modifier(); diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs index 16c6ed8b..21d1b2e9 100644 --- a/azalea-brigadier/src/context/parsed_command_node.rs +++ b/azalea-brigadier/src/context/parsed_command_node.rs @@ -1,17 +1,17 @@ use super::string_range::StringRange; -use crate::tree::command_node::CommandNode; +use crate::tree::command_node::CommandNodeTrait; pub struct ParsedCommandNode<S> { - node: Box<dyn CommandNode<S>>, + node: Box<dyn CommandNodeTrait<S>>, range: StringRange, } impl<S> ParsedCommandNode<S> { - fn new(node: dyn CommandNode<S>, range: StringRange) -> Self { + fn new(node: dyn CommandNodeTrait<S>, range: StringRange) -> Self { Self { node, range } } - fn node(&self) -> &dyn CommandNode<S> { + fn node(&self) -> &dyn CommandNodeTrait<S> { &self.node } diff --git a/azalea-brigadier/src/context/suggestion_context.rs b/azalea-brigadier/src/context/suggestion_context.rs index 252cb6ed..51a053c1 100644 --- a/azalea-brigadier/src/context/suggestion_context.rs +++ b/azalea-brigadier/src/context/suggestion_context.rs @@ -1,6 +1,6 @@ -use crate::tree::command_node::CommandNode; +use crate::tree::command_node::CommandNodeTrait; pub struct SuggestionContext<'a, S> { - parent: &'a dyn CommandNode<S>, + parent: &'a dyn CommandNodeTrait<S>, start_pos: usize, } diff --git a/azalea-brigadier/src/string_reader.rs b/azalea-brigadier/src/string_reader.rs index f32de473..694edccb 100644 --- a/azalea-brigadier/src/string_reader.rs +++ b/azalea-brigadier/src/string_reader.rs @@ -9,7 +9,7 @@ use std::str::FromStr; #[derive(Clone)] pub struct StringReader<'a> { string: &'a str, - cursor: usize, + pub cursor: usize, } const SYNTAX_ESCAPE: char = '\\'; @@ -18,9 +18,15 @@ const SYNTAX_SINGLE_QUOTE: char = '\''; // impl<'a> From<&'a str> for &StringReader<'a> {} -impl StringReader<'_> { - fn from(string: &str) -> StringReader { - StringReader { string, cursor: 0 } +// impl StringReader<'_> { +// fn from(string: &str) -> StringReader { +// StringReader { string, cursor: 0 } +// } +// } + +impl<'a> From<&'a str> for StringReader<'a> { + fn from(string: &'a str) -> Self { + Self { string, cursor: 0 } } } diff --git a/azalea-brigadier/src/tree/argument_command_node.rs b/azalea-brigadier/src/tree/argument_command_node.rs index e33c3d3e..0997ec17 100644 --- a/azalea-brigadier/src/tree/argument_command_node.rs +++ b/azalea-brigadier/src/tree/argument_command_node.rs @@ -1,17 +1,20 @@ use std::{ any::Any, - fmt::{Display, Formatter}, + collections::HashMap, + fmt::{Debug, Display, Formatter}, }; use crate::{ arguments::argument_type::ArgumentType, builder::required_argument_builder::RequiredArgumentBuilder, + command::Command, context::{ command_context::CommandContext, command_context_builder::CommandContextBuilder, parsed_argument::ParsedArgument, }, exceptions::command_syntax_exception::CommandSyntaxException, immutable_string_reader::ImmutableStringReader, + redirect_modifier::RedirectModifier, string_reader::StringReader, suggestion::{ suggestion_provider::SuggestionProvider, suggestions::Suggestions, @@ -19,12 +22,16 @@ use crate::{ }, }; -use super::command_node::{BaseCommandNode, CommandNode}; +use super::{ + command_node::{BaseCommandNode, CommandNodeTrait}, + literal_command_node::LiteralCommandNode, + root_command_node::RootCommandNode, +}; const USAGE_ARGUMENT_OPEN: &str = "<"; const USAGE_ARGUMENT_CLOSE: &str = ">"; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct ArgumentCommandNode<'a, S> { name: String, type_: Box<dyn ArgumentType<Into = dyn Any>>, @@ -32,6 +39,15 @@ pub struct ArgumentCommandNode<'a, S> { // custom_suggestions: &'a dyn SuggestionProvider<S>, // Since Rust doesn't have extending, we put the struct this is extending as the "base" field pub base: BaseCommandNode<'a, S>, + + children: HashMap<String, Box<dyn CommandNodeTrait<S>>>, + literals: HashMap<String, LiteralCommandNode<'a, S>>, + arguments: HashMap<String, ArgumentCommandNode<'a, S>>, + pub requirement: Box<dyn Fn(&S) -> bool>, + redirect: Option<Box<dyn CommandNodeTrait<S>>>, + modifier: Option<Box<dyn RedirectModifier<S>>>, + forks: bool, + pub command: Option<Box<dyn Command<S>>>, } impl<S> ArgumentCommandNode<'_, S> { @@ -44,10 +60,7 @@ impl<S> ArgumentCommandNode<'_, S> { } } -impl<'a, S> CommandNode<S> for ArgumentCommandNode<'a, S> -where - S: Clone, -{ +impl<'a, S> CommandNodeTrait<S> for ArgumentCommandNode<'a, S> { fn name(&self) -> &str { &self.name } @@ -119,8 +132,44 @@ where self.type_.get_examples() } - fn base(&self) -> &BaseCommandNode<S> { - &self.base + fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> { + self.modifier.as_ref().map(|modifier| modifier.as_ref()) + } + + fn can_use(&self, source: S) -> bool { + (self.requirement)(&source) + } + + fn add_child(&self, node: &Box<dyn CommandNodeTrait<S>>) -> Result<(), String> { + let dynamic_node = node as &dyn Any; + if dynamic_node.is::<RootCommandNode<S>>() { + return Err(String::from( + "Cannot add a RootCommandNode as a child to any other CommandNode", + )); + } + + let mut 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.base_mut().command = Some(*command); + } + for grandchild in node.base().children().values() { + child.base_mut().add_child(&*grandchild)?; + } + Ok(()) + } else { + self.children.insert(node.name().to_string(), *node); + + if let Some(dynamic_node) = dynamic_node.downcast_ref::<LiteralCommandNode<S>>() { + self.literals.insert(node.name().to_string(), *dynamic_node); + } else if let Some(dynamic_node) = dynamic_node.downcast_ref::<ArgumentCommandNode<S>>() + { + self.arguments + .insert(node.name().to_string(), *dynamic_node); + } + Ok(()) + } } } diff --git a/azalea-brigadier/src/tree/command_node.rs b/azalea-brigadier/src/tree/command_node.rs index f59b1cef..b7801363 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -12,117 +12,112 @@ use crate::{ string_reader::StringReader, suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, }; -use dyn_clonable::*; +use std::ops::Deref; use std::{any::Any, collections::HashMap, fmt::Debug}; -pub struct BaseCommandNode<'a, S> { - children: HashMap<String, Box<dyn CommandNode<S>>>, - literals: HashMap<String, LiteralCommandNode<'a, S>>, - arguments: HashMap<String, ArgumentCommandNode<'a, S>>, - requirement: Box<dyn Fn(&S) -> bool>, - redirect: Option<Box<dyn CommandNode<S>>>, - modifier: Option<Box<dyn RedirectModifier<S>>>, - forks: bool, - command: Option<Box<dyn Command<S>>>, +enum CommandNodeEnum<'a, S> { + Literal(LiteralCommandNode<'a, S>), + Argument(ArgumentCommandNode<'a, S>), + Root(RootCommandNode<'a, S>), } -impl<S> BaseCommandNode<'_, S> { - pub fn command(&self) -> &Option<Box<dyn Command<S>>> { - &self.command +impl<S> Deref for CommandNodeEnum<'_, S> { + type Target = dyn CommandNodeTrait<S>; + + fn deref(&self) -> &Self::Target { + match self { + CommandNodeEnum::Literal(node) => node, + CommandNodeEnum::Argument(node) => node, + CommandNodeEnum::Root(node) => node, + } } +} - pub fn children(&self) -> &HashMap<String, Box<dyn CommandNode<S>>> { - &self.children +impl<S> From<LiteralCommandNode<'_, S>> for CommandNodeEnum<'_, S> { + fn from(node: LiteralCommandNode<'_, S>) -> Self { + CommandNodeEnum::Literal(node) } +} - pub fn child(&self, name: &str) -> Option<&dyn CommandNode<S>> { - self.children.get(name).map(|child| child.as_ref()) +impl<S> From<ArgumentCommandNode<'_, S>> for CommandNodeEnum<'_, S> { + fn from(node: ArgumentCommandNode<'_, S>) -> Self { + CommandNodeEnum::Argument(node) } +} - pub fn redirect(&self) -> Option<&dyn CommandNode<S>> { - self.redirect.as_ref().map(|redirect| redirect.as_ref()) +impl<S> From<RootCommandNode<'_, S>> for CommandNodeEnum<'_, S> { + fn from(node: RootCommandNode<'_, S>) -> Self { + CommandNodeEnum::Root(node) } +} - pub fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> { - self.modifier.as_ref().map(|modifier| modifier.as_ref()) +impl<S> CommandNodeEnum<'_, S> { + 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 { + 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>>() { + fn add_child(&self, node: &Box<dyn CommandNodeTrait<S>>) -> Result<(), String> { + let dynamic_node = node as &dyn Any; + if dynamic_node.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()); + let mut 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); + if let Some(command) = node.base().command() { + child.base_mut().command = Some(*command); } - for grandchild in node.children() { - child.add_child(grandchild)?; + for grandchild in node.base().children().values() { + child.base_mut().add_child(&*grandchild)?; } + Ok(()) } 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.children.insert(node.name().to_string(), *node); + + if let Some(dynamic_node) = dynamic_node.downcast_ref::<LiteralCommandNode<S>>() { + self.literals.insert(node.name().to_string(), *dynamic_node); + } else if let Some(dynamic_node) = dynamic_node.downcast_ref::<ArgumentCommandNode<S>>() { self.arguments - .insert(node.name().to_string(), argument.clone_boxed()); + .insert(node.name().to_string(), *dynamic_node); } + Ok(()) } } } - -impl<S> Clone for BaseCommandNode<'_, S> { - fn clone(&self) -> Self { - Self { - children: self.children.clone(), - literals: self.literals.clone(), - arguments: self.arguments.clone(), - requirement: self.requirement.clone(), - redirect: self.redirect.clone(), - modifier: self.modifier.clone(), - forks: self.forks.clone(), - command: self.command.clone(), - } - } +pub struct BaseCommandNode<'a, S> { + children: HashMap<String, Box<dyn CommandNodeTrait<S>>>, + literals: HashMap<String, LiteralCommandNode<'a, S>>, + arguments: HashMap<String, ArgumentCommandNode<'a, S>>, + pub requirement: Box<dyn Fn(&S) -> bool>, + redirect: Option<Box<dyn CommandNodeTrait<S>>>, + modifier: Option<Box<dyn RedirectModifier<S>>>, + forks: bool, + pub command: Option<Box<dyn Command<S>>>, } +// impl<S> Clone for BaseCommandNode<'_, S> { +// fn clone(&self) -> Self { +// Self { +// children: self.children.clone(), +// literals: self.literals.clone(), +// arguments: self.arguments.clone(), +// requirement: self.requirement.clone(), +// redirect: self.redirect.clone(), +// modifier: self.modifier.clone(), +// forks: self.forks.clone(), +// command: self.command.clone(), +// } +// } +// } + impl<S> Debug for BaseCommandNode<'_, S> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("BaseCommandNode") @@ -153,7 +148,7 @@ impl<S> Default for BaseCommandNode<'_, S> { } } -pub trait CommandNode<S> { +pub trait CommandNodeTrait<S> { fn name(&self) -> &str; fn usage_text(&self) -> &str; fn parse( @@ -167,7 +162,6 @@ pub trait CommandNode<S> { builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException>; fn is_valid_input(&self, input: &str) -> bool; - fn create_builder(&self) -> dyn ArgumentBuilder<S, dyn Any>; + fn create_builder(&self) -> Box<dyn ArgumentBuilder<S>>; fn get_examples(&self) -> Vec<String>; - fn base(&self) -> &BaseCommandNode<S>; } diff --git a/azalea-brigadier/src/tree/literal_command_node.rs b/azalea-brigadier/src/tree/literal_command_node.rs index a722121f..253b6dc5 100644 --- a/azalea-brigadier/src/tree/literal_command_node.rs +++ b/azalea-brigadier/src/tree/literal_command_node.rs @@ -1,17 +1,19 @@ use crate::{ arguments::argument_type::ArgumentType, - builder::literal_argument_builder::LiteralArgumentBuilder, - command::Command, + builder::{ + argument_builder::ArgumentBuilder, literal_argument_builder::LiteralArgumentBuilder, + }, context::{command_context::CommandContext, command_context_builder::CommandContextBuilder}, exceptions::{ builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, }, - redirect_modifier::RedirectModifier, + immutable_string_reader::ImmutableStringReader, string_reader::StringReader, suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, }; +use std::fmt::Debug; -use super::command_node::{BaseCommandNode, CommandNode}; +use super::command_node::{BaseCommandNode, CommandNodeTrait}; #[derive(Debug, Clone)] pub struct LiteralCommandNode<'a, S> { @@ -22,7 +24,7 @@ pub struct LiteralCommandNode<'a, S> { } impl<'a, S> LiteralCommandNode<'a, S> { - pub fn new(literal: String, base: BaseCommandNode<S>) -> Self { + pub fn new(literal: String, base: BaseCommandNode<'a, S>) -> Self { let literal_lowercase = literal.to_lowercase(); Self { literal, @@ -35,16 +37,16 @@ impl<'a, S> LiteralCommandNode<'a, S> { &self.literal } - pub fn parse(&self, reader: StringReader) -> i32 { - let start = reader.get_cursor(); - if reader.can_read(self.literal.len()) { + pub fn parse(&self, reader: &mut StringReader) -> i32 { + let start = reader.cursor(); + if reader.can_read_length(self.literal.len()) { let end = start + self.literal.len(); - if reader.get_string()[start..end].eq(&self.literal) { - reader.set_cursor(end); + if reader.string()[start..end].eq(&self.literal) { + reader.cursor = end; if !reader.can_read() || reader.peek() == ' ' { return end as i32; } else { - reader.set_cursor(start); + reader.cursor = start; } } } @@ -52,27 +54,24 @@ impl<'a, S> LiteralCommandNode<'a, S> { } } -impl<S> CommandNode<S> for LiteralCommandNode<'_, S> -where - S: Clone, -{ +impl<S> CommandNodeTrait<S> for LiteralCommandNode<'_, S> { fn name(&self) -> &str { &self.literal } fn parse( &self, - reader: StringReader, + reader: &mut StringReader<'_>, context_builder: CommandContextBuilder<S>, ) -> Result<(), CommandSyntaxException> { - let start = reader.get_cursor(); + let start = reader.cursor(); let end = self.parse(reader); if end > -1 { return Ok(()); } Err(BuiltInExceptions::LiteralIncorrect { - expected: self.literal(), + expected: self.literal().to_string(), } .create_with_context(reader)) } @@ -80,33 +79,41 @@ where fn list_suggestions( &self, context: CommandContext<S>, - builder: SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException> { if self .literal_lowercase .starts_with(&builder.remaining_lowercase()) { - builder.suggest(self.literal()) + Ok(builder.suggest(self.literal()).build()) } else { - Suggestions::empty() + Ok(Suggestions::default()) } } fn is_valid_input(&self, input: &str) -> bool { - self.parse(StringReader::from(input)) > -1 + self.parse(&mut StringReader::from(input)) > -1 } fn usage_text(&self) -> &str { - self.literal + &self.literal } - fn create_builder(&self) -> LiteralArgumentBuilder<S> { - let builder = LiteralArgumentBuilder::literal(self.literal()); - builder.requires(self.requirement()); - builder.forward(self.redirect(), self.redirect_modifier(), self.is_fork()); + fn create_builder(&self) -> Box<dyn ArgumentBuilder<S>> { + let mut builder = LiteralArgumentBuilder::literal(self.literal().to_string()); + builder.base.requires(&self.base().requirement); + builder.base.forward( + self.base.redirect(), + self.base.redirect_modifier(), + self.base.is_fork(), + ); if self.command().is_some() { builder.executes(self.command().unwrap()); } builder } + + fn get_examples(&self) -> Vec<String> { + todo!() + } } diff --git a/azalea-brigadier/src/tree/root_command_node.rs b/azalea-brigadier/src/tree/root_command_node.rs index c3139a05..0fcb8d97 100644 --- a/azalea-brigadier/src/tree/root_command_node.rs +++ b/azalea-brigadier/src/tree/root_command_node.rs @@ -1,44 +1,49 @@ -use std::fmt::{Display, Formatter}; - +use super::{ + argument_command_node::ArgumentCommandNode, + command_node::{BaseCommandNode, CommandNodeTrait}, + literal_command_node::LiteralCommandNode, +}; use crate::{ arguments::argument_type::ArgumentType, + builder::argument_builder::ArgumentBuilder, context::{command_context::CommandContext, command_context_builder::CommandContextBuilder}, exceptions::{ builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, }, + redirect_modifier::RedirectModifier, string_reader::StringReader, suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, }; +use std::{ + any::Any, + fmt::{Debug, Display, Formatter}, +}; -use super::command_node::{BaseCommandNode, CommandNode}; - -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct RootCommandNode<'a, S> { // Since Rust doesn't have extending, we put the struct this is extending as the "base" field pub base: BaseCommandNode<'a, S>, } -impl<S> CommandNode<S> for RootCommandNode<'_, S> -where - S: Clone, -{ +impl<S> CommandNodeTrait<S> for RootCommandNode<'_, S> { fn name(&self) -> &str { "" } fn parse( &self, - reader: StringReader, + reader: &mut StringReader<'_>, context_builder: CommandContextBuilder<S>, ) -> Result<(), CommandSyntaxException> { + Ok(()) } fn list_suggestions( &self, context: CommandContext<S>, - builder: SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException> { - Suggestions::empty() + Ok(Suggestions::default()) } fn is_valid_input(&self, input: &str) -> bool { @@ -49,7 +54,7 @@ where "" } - fn create_builder(&self) -> () { + fn create_builder(&self) -> Box<dyn ArgumentBuilder<S>> { panic!("Cannot convert root into a builder"); } |
