diff --git a/Cargo.lock b/Cargo.lock index a0ca81fb..d52792ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,7 @@ name = "azalea-brigadier" version = "0.1.0" dependencies = [ "dyn-clonable", + "enum_dispatch", "lazy_static", ] @@ -382,6 +383,18 @@ dependencies = [ "syn", ] +[[package]] +name = "enum_dispatch" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "flate2" version = "1.0.22" @@ -717,6 +730,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + [[package]] name = "oorandom" version = "11.1.3" diff --git a/azalea-brigadier/Cargo.toml b/azalea-brigadier/Cargo.toml index 4e8968d7..6dead502 100644 --- a/azalea-brigadier/Cargo.toml +++ b/azalea-brigadier/Cargo.toml @@ -8,3 +8,4 @@ version = "0.1.0" [dependencies] lazy_static = "^1.4" dyn-clonable = "^0.9" +enum_dispatch = "^0.3" diff --git a/azalea-brigadier/src/builder/literal_argument_builder.rs b/azalea-brigadier/src/builder/literal_argument_builder.rs index 8250d45d..4a95755c 100644 --- a/azalea-brigadier/src/builder/literal_argument_builder.rs +++ b/azalea-brigadier/src/builder/literal_argument_builder.rs @@ -10,11 +10,8 @@ use crate::{ }; use std::fmt::Debug; -pub struct LiteralArgumentBuilder<'a, S> -where - , -{ - arguments: RootCommandNode<'a, S>, +pub struct LiteralArgumentBuilder { + arguments: RootCommandNode, command: Option>>, requirement: Box bool>, target: Option>>, @@ -23,10 +20,7 @@ where literal: String, } -impl<'a, S> LiteralArgumentBuilder<'a, S> -where - , -{ +impl LiteralArgumentBuilder { pub fn new(literal: String) -> Self { Self { literal, @@ -44,10 +38,7 @@ where } } -impl<'a, S> ArgumentBuilder for LiteralArgumentBuilder<'a, S> -where - , -{ +impl ArgumentBuilder for LiteralArgumentBuilder { fn build(self) -> Box> { let result = LiteralCommandNode::new(self.literal, self.base.build()); diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs index 98288a48..f8ffddff 100644 --- a/azalea-brigadier/src/command_dispatcher.rs +++ b/azalea-brigadier/src/command_dispatcher.rs @@ -4,11 +4,11 @@ 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 #[derive(Default, Clone)] -pub struct CommandDispatcher<'a, S> { - root: RootCommandNode<'a, S>, +pub struct CommandDispatcher { + root: RootCommandNode, } -impl CommandDispatcher<'_, S> { +impl CommandDispatcher { /// The string required to separate individual arguments in an input string /// /// See: [`ARGUMENT_SEPARATOR_CHAR`] diff --git a/azalea-brigadier/src/lib.rs b/azalea-brigadier/src/lib.rs index b2345abb..a1ac267c 100644 --- a/azalea-brigadier/src/lib.rs +++ b/azalea-brigadier/src/lib.rs @@ -1,6 +1,9 @@ #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate enum_dispatch; + mod ambiguity_consumer; mod arguments; mod builder; diff --git a/azalea-brigadier/src/tree/argument_command_node.rs b/azalea-brigadier/src/tree/argument_command_node.rs index 0997ec17..9d2af14e 100644 --- a/azalea-brigadier/src/tree/argument_command_node.rs +++ b/azalea-brigadier/src/tree/argument_command_node.rs @@ -31,18 +31,14 @@ use super::{ const USAGE_ARGUMENT_OPEN: &str = "<"; const USAGE_ARGUMENT_CLOSE: &str = ">"; -#[derive(Clone, Debug)] -pub struct ArgumentCommandNode<'a, S> { +pub struct ArgumentCommandNode { name: String, type_: Box>, - custom_suggestions: Option<&'a dyn SuggestionProvider>, - // custom_suggestions: &'a dyn SuggestionProvider, - // Since Rust doesn't have extending, we put the struct this is extending as the "base" field - pub base: BaseCommandNode<'a, S>, + custom_suggestions: Option>>, children: HashMap>>, - literals: HashMap>, - arguments: HashMap>, + literals: HashMap>, + arguments: HashMap>, pub requirement: Box bool>, redirect: Option>>, modifier: Option>>, @@ -50,17 +46,17 @@ pub struct ArgumentCommandNode<'a, S> { pub command: Option>>, } -impl ArgumentCommandNode<'_, S> { +impl ArgumentCommandNode { fn get_type(&self) -> &dyn ArgumentType { - self.type_ + &*self.type_ } - fn custom_suggestions(&self) -> Option<&dyn SuggestionProvider> { - self.custom_suggestions + fn custom_suggestions(&self) -> &Option>> { + &self.custom_suggestions } } -impl<'a, S> CommandNodeTrait for ArgumentCommandNode<'a, S> { +impl CommandNodeTrait for ArgumentCommandNode { fn name(&self) -> &str { &self.name } @@ -173,7 +169,7 @@ impl<'a, S> CommandNodeTrait for ArgumentCommandNode<'a, S> { } } -impl Display for ArgumentCommandNode<'_, S> { +impl Display for ArgumentCommandNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "", self.name, self.type_) } diff --git a/azalea-brigadier/src/tree/command_node.rs b/azalea-brigadier/src/tree/command_node.rs index 30907163..207e114e 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -15,43 +15,14 @@ use crate::{ use std::ops::Deref; use std::{any::Any, collections::HashMap, fmt::Debug}; -enum CommandNodeEnum<'a, S> { - Literal(LiteralCommandNode<'a, S>), - Argument(ArgumentCommandNode<'a, S>), - Root(RootCommandNode<'a, S>), +#[enum_dispatch(CommandNodeTrait)] +enum CommandNodeEnum { + Literal(LiteralCommandNode), + Argument(ArgumentCommandNode), + Root(RootCommandNode), } -impl<'a, S> Deref for CommandNodeEnum<'a, S> { - type Target = dyn CommandNodeTrait; - - fn deref(&self) -> &Self::Target { - match self { - CommandNodeEnum::Literal(node) => *node as &Self::Target, - CommandNodeEnum::Argument(node) => *node as &Self::Target, - CommandNodeEnum::Root(node) => *node as &Self::Target, - } - } -} - -impl From> for CommandNodeEnum<'_, S> { - fn from(node: LiteralCommandNode<'_, S>) -> Self { - CommandNodeEnum::Literal(node) - } -} - -impl From> for CommandNodeEnum<'_, S> { - fn from(node: ArgumentCommandNode<'_, S>) -> Self { - CommandNodeEnum::Argument(node) - } -} - -impl From> for CommandNodeEnum<'_, S> { - fn from(node: RootCommandNode<'_, S>) -> Self { - CommandNodeEnum::Root(node) - } -} - -impl CommandNodeEnum<'_, S> { +impl CommandNodeEnum { fn redirect_modifier(&self) -> Option<&dyn RedirectModifier> { (*self).modifier.as_ref().map(|modifier| modifier.as_ref()) } @@ -92,10 +63,10 @@ impl CommandNodeEnum<'_, S> { } } } -pub struct BaseCommandNode<'a, S> { +pub struct BaseCommandNode { children: HashMap>>, - literals: HashMap>, - arguments: HashMap>, + literals: HashMap>, + arguments: HashMap>, pub requirement: Box bool>, redirect: Option>>, modifier: Option>>, @@ -118,7 +89,7 @@ pub struct BaseCommandNode<'a, S> { // } // } -impl Debug for BaseCommandNode<'_, S> { +impl Debug for BaseCommandNode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("BaseCommandNode") .field("children", &self.children) @@ -133,7 +104,7 @@ impl Debug for BaseCommandNode<'_, S> { } } -impl Default for BaseCommandNode<'_, S> { +impl Default for BaseCommandNode { fn default() -> Self { Self { children: HashMap::new(), @@ -148,6 +119,7 @@ impl Default for BaseCommandNode<'_, S> { } } +#[enum_dispatch] pub trait CommandNodeTrait { fn name(&self) -> &str; fn usage_text(&self) -> &str; @@ -164,4 +136,8 @@ pub trait CommandNodeTrait { fn is_valid_input(&self, input: &str) -> bool; fn create_builder(&self) -> Box>; fn get_examples(&self) -> Vec; + + fn redirect_modifier(&self) -> Option<&dyn RedirectModifier>; + fn can_use(&self, source: S) -> bool; + fn add_child(&self, node: &Box>) -> Result<(), String>; } diff --git a/azalea-brigadier/src/tree/literal_command_node.rs b/azalea-brigadier/src/tree/literal_command_node.rs index 253b6dc5..2db31d97 100644 --- a/azalea-brigadier/src/tree/literal_command_node.rs +++ b/azalea-brigadier/src/tree/literal_command_node.rs @@ -3,33 +3,45 @@ use crate::{ builder::{ argument_builder::ArgumentBuilder, literal_argument_builder::LiteralArgumentBuilder, }, + command::Command, context::{command_context::CommandContext, command_context_builder::CommandContextBuilder}, exceptions::{ builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, }, immutable_string_reader::ImmutableStringReader, + redirect_modifier::RedirectModifier, string_reader::StringReader, suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, }; -use std::fmt::Debug; +use std::{collections::HashMap, fmt::Debug}; -use super::command_node::{BaseCommandNode, CommandNodeTrait}; +use super::{ + argument_command_node::ArgumentCommandNode, + command_node::{BaseCommandNode, CommandNodeTrait}, +}; #[derive(Debug, Clone)] -pub struct LiteralCommandNode<'a, S> { +pub struct LiteralCommandNode { literal: String, literal_lowercase: String, - // Since Rust doesn't have extending, we put the struct this is extending as the "base" field - pub base: BaseCommandNode<'a, S>, + + children: HashMap>>, + literals: HashMap>, + arguments: HashMap>, + pub requirement: Box bool>, + redirect: Option>>, + modifier: Option>>, + forks: bool, + pub command: Option>>, } -impl<'a, S> LiteralCommandNode<'a, S> { - pub fn new(literal: String, base: BaseCommandNode<'a, S>) -> Self { +impl LiteralCommandNode { + pub fn new(literal: String) -> Self { let literal_lowercase = literal.to_lowercase(); Self { literal, literal_lowercase, - base, + ..Default::default() } } @@ -54,7 +66,7 @@ impl<'a, S> LiteralCommandNode<'a, S> { } } -impl CommandNodeTrait for LiteralCommandNode<'_, S> { +impl CommandNodeTrait for LiteralCommandNode { fn name(&self) -> &str { &self.literal } diff --git a/azalea-brigadier/src/tree/root_command_node.rs b/azalea-brigadier/src/tree/root_command_node.rs index 0fcb8d97..6b8bc157 100644 --- a/azalea-brigadier/src/tree/root_command_node.rs +++ b/azalea-brigadier/src/tree/root_command_node.rs @@ -6,6 +6,7 @@ use super::{ use crate::{ arguments::argument_type::ArgumentType, builder::argument_builder::ArgumentBuilder, + command::Command, context::{command_context::CommandContext, command_context_builder::CommandContextBuilder}, exceptions::{ builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException, @@ -16,16 +17,24 @@ use crate::{ }; use std::{ any::Any, + collections::HashMap, fmt::{Debug, Display, Formatter}, }; -#[derive(Clone, Default, Debug)] -pub struct RootCommandNode<'a, S> { +#[derive(Default)] +pub struct RootCommandNode { // Since Rust doesn't have extending, we put the struct this is extending as the "base" field - pub base: BaseCommandNode<'a, S>, + children: HashMap>>, + literals: HashMap>, + arguments: HashMap>, + pub requirement: Box bool>, + redirect: Option>>, + modifier: Option>>, + forks: bool, + pub command: Option>>, } -impl CommandNodeTrait for RootCommandNode<'_, S> { +impl CommandNodeTrait for RootCommandNode { fn name(&self) -> &str { "" } @@ -63,7 +72,7 @@ impl CommandNodeTrait for RootCommandNode<'_, S> { } } -impl Display for RootCommandNode<'_, S> { +impl Display for RootCommandNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "") }