aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--azalea-brigadier/src/builder/argument_builder.rs37
-rw-r--r--azalea-brigadier/src/builder/literal_argument_builder.rs29
-rw-r--r--azalea-brigadier/src/builder/required_argument_builder.rs35
-rw-r--r--azalea-brigadier/src/command_dispatcher.rs1
-rw-r--r--azalea-brigadier/src/context/command_context.rs4
-rw-r--r--azalea-brigadier/src/context/command_context_builder.rs21
-rw-r--r--azalea-brigadier/src/context/parsed_command_node.rs8
-rw-r--r--azalea-brigadier/src/context/suggestion_context.rs4
-rw-r--r--azalea-brigadier/src/string_reader.rs14
-rw-r--r--azalea-brigadier/src/tree/argument_command_node.rs67
-rw-r--r--azalea-brigadier/src/tree/command_node.rs152
-rw-r--r--azalea-brigadier/src/tree/literal_command_node.rs61
-rw-r--r--azalea-brigadier/src/tree/root_command_node.rs31
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");
}