diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs index f5ca457b..107b1cbf 100644 --- a/azalea-brigadier/src/arguments/argument_type.rs +++ b/azalea-brigadier/src/arguments/argument_type.rs @@ -6,27 +6,30 @@ use crate::{ suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, }; -pub enum DefaultArguments { - Bool(BoolArgumentType), +pub trait Types { + fn bool(value: bool) -> Self; } /* -define_arguments! { +#[derive(Types)] +enum BrigadierTypes { Entity(EntityArgumentType) } === -enum CustomArguments { +enum BrigadierTypes { + Bool(BoolArgumentType) + Entity(EntityArgumentType) } -enum BrigadierArguments { - BuiltIn(DefaultArguments) - Custom(CustomArguments) -} */ -pub trait ArgumentType { +pub trait ArgumentType +where + Self: Sized, + T: Types, +{ // T parse(StringReader reader) throws CommandSyntaxException; // default CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { @@ -41,9 +44,12 @@ pub trait ArgumentType { fn list_suggestions( &self, - context: &CommandContext, + context: &CommandContext, builder: &mut SuggestionsBuilder, - ) -> Result; + ) -> Result + where + S: Sized, + T: Sized; fn get_examples(&self) -> Vec; } diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs index 9bdf42e5..dc2c6896 100644 --- a/azalea-brigadier/src/arguments/bool_argument_type.rs +++ b/azalea-brigadier/src/arguments/bool_argument_type.rs @@ -1,10 +1,51 @@ -use crate::context::command_context::CommandContext; +use crate::{ + context::command_context::CommandContext, + exceptions::command_syntax_exception::CommandSyntaxException, + string_reader::StringReader, + suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}, +}; -use super::argument_type::ArgumentType; +use super::argument_type::{ArgumentType, Types}; pub struct BoolArgumentType {} -impl ArgumentType for BoolArgumentType {} +impl ArgumentType for BoolArgumentType +where + T: Types, +{ + fn parse(&self, reader: &mut StringReader) -> Result { + Ok(T::bool(reader.read_boolean()?)) + } + + fn list_suggestions( + &self, + context: &CommandContext, + builder: &mut SuggestionsBuilder, + ) -> Result + where + S: Sized, + T: Sized, + { + // if ("true".startsWith(builder.getRemainingLowerCase())) { + // builder.suggest("true"); + // } + // if ("false".startsWith(builder.getRemainingLowerCase())) { + // builder.suggest("false"); + // } + // return builder.buildFuture(); + if "true".starts_with(builder.get_remaining_lower_case()) { + builder.suggest("true"); + } + if "false".starts_with(builder.get_remaining_lower_case()) { + builder.suggest("false"); + } + Ok(builder.build_future()) + } + + fn get_examples(&self) -> Vec { + vec![] + } +} impl BoolArgumentType { const EXAMPLES: &'static [&'static str] = &["true", "false"]; @@ -13,7 +54,7 @@ impl BoolArgumentType { Self {} } - fn get_bool(context: CommandContext, name: String) { + fn get_bool(context: CommandContext, name: String) { context.get_argument::(name) } } diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index 19706a22..bd2a2c15 100644 --- a/azalea-brigadier/src/builder/argument_builder.rs +++ b/azalea-brigadier/src/builder/argument_builder.rs @@ -5,27 +5,25 @@ use crate::{ tree::{command_node::CommandNode, root_command_node::RootCommandNode}, }; -pub struct BaseArgumentBuilder +pub struct BaseArgumentBuilder<'a, S, T> where - T: ArgumentBuilder, + S: Sized, + T: Sized, { - arguments: RootCommandNode, - command: Option>, - requirement: dyn Fn(&S) -> bool, - target: Option>, - modifier: Option>, + arguments: RootCommandNode<'a, S, T>, + command: Option<&'a dyn Command>, + requirement: &'a dyn Fn(&S) -> bool, + target: Option<&'a dyn CommandNode>, + modifier: Option<&'a dyn RedirectModifier>, forks: bool, } pub trait ArgumentBuilder { - fn build(self) -> dyn CommandNode; + fn build(self) -> dyn CommandNode; } -impl BaseArgumentBuilder -where - T: ArgumentBuilder, -{ - pub fn then(&mut self, command: dyn CommandNode) -> Result<&mut T, String> { +impl BaseArgumentBuilder<'_, S, T> { + pub fn then(&mut self, command: dyn CommandNode) -> Result<&mut T, String> { if self.target.is_some() { return Err("Cannot add children to a redirected node".to_string()); } @@ -33,20 +31,20 @@ where Ok(self) } - pub fn arguments(&self) -> &Vec> { + pub fn arguments(&self) -> &Vec<&dyn CommandNode> { &self.arguments.get_children() } - pub fn executes(&mut self, command: dyn Command) -> &mut T { + pub fn executes(&mut self, command: dyn Command) -> &mut T { self.command = command; self } - pub fn command(&self) -> dyn Command { + pub fn command(&self) -> dyn Command { self.command } - pub fn requires(&mut self, requirement: dyn Fn(&S) -> bool) -> &mut T { + pub fn requires(&mut self, requirement: &dyn Fn(&S) -> bool) -> &mut T { self.requirement = requirement; self } @@ -55,14 +53,14 @@ where self.requirement } - pub fn redirect(&mut self, target: dyn CommandNode) -> &mut T { + pub fn redirect(&mut self, target: &dyn CommandNode) -> &mut T { self.forward(target, None, false) } pub fn redirect_modifier( &mut self, - target: dyn CommandNode, - modifier: dyn SingleRedirectModifier, + target: &dyn CommandNode, + modifier: &dyn SingleRedirectModifier, ) -> &mut T { // forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false); self.forward(target, modifier.map(|m| |o| vec![m.apply(o)]), false) @@ -70,16 +68,16 @@ where pub fn fork( &mut self, - target: dyn CommandNode, - modifier: dyn RedirectModifier, + target: &dyn CommandNode, + modifier: &dyn RedirectModifier, ) -> &mut T { self.forward(target, Some(modifier), true) } pub fn forward( &mut self, - target: dyn CommandNode, - modifier: Option>, + target: &dyn CommandNode, + modifier: Option<&dyn RedirectModifier>, fork: bool, ) -> Result<&mut T, String> { if !self.arguments.get_children().is_empty() { @@ -91,11 +89,11 @@ where Ok(self) } - pub fn get_redirect(&self) -> Option<&dyn CommandNode> { + pub fn get_redirect(&self) -> Option<&dyn CommandNode> { self.target.as_ref() } - pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier> { + pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier> { self.modifier.as_ref() } diff --git a/azalea-brigadier/src/builder/literal_argument_builder.rs b/azalea-brigadier/src/builder/literal_argument_builder.rs index e69de29b..cf9f1ee9 100644 --- a/azalea-brigadier/src/builder/literal_argument_builder.rs +++ b/azalea-brigadier/src/builder/literal_argument_builder.rs @@ -0,0 +1,32 @@ +use crate::tree::literal_command_node::LiteralCommandNode; + +use super::argument_builder::BaseArgumentBuilder; + +pub struct LiteralArgumentBuilder<'a, S, T> { + literal: String, + + pub base: BaseArgumentBuilder<'a, S, T>, +} + +impl<'a, S, T> LiteralArgumentBuilder<'a, S, T> { + pub fn new(literal: String) -> Self { + Self { + literal, + base: BaseArgumentBuilder::default(), + } + } + + pub fn literal(name: String) -> Self { + Self::new(name) + } + + pub fn build(self) -> LiteralCommandNode<'a, S, T> { + let result = LiteralCommandNode::new(self.literal, self.base); + + for argument in self.base.arguments { + result.add_child(argument); + } + + result + } +} diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index 3ec613c4..6f6fa8eb 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -1,92 +1,50 @@ use crate::{ - arguments::argument_type::ArgumentType, suggestion::suggestion_provider::SuggestionProvider, tree::{argument_command_node::ArgumentCommandNode, command_node::BaseCommandNode}, }; use super::argument_builder::BaseArgumentBuilder; -// private RequiredArgumentBuilder(final String name, final ArgumentType type) { -// this.name = name; -// this.type = type; -// } - -// public static RequiredArgumentBuilder argument(final String name, final ArgumentType type) { -// return new RequiredArgumentBuilder<>(name, type); -// } - -// public RequiredArgumentBuilder suggests(final SuggestionProvider provider) { -// this.suggestionsProvider = provider; -// return getThis(); -// } - -// public SuggestionProvider getSuggestionsProvider() { -// return suggestionsProvider; -// } - -// @Override -// protected RequiredArgumentBuilder getThis() { -// return this; -// } - -// public ArgumentType getType() { -// return type; -// } - -// public String getName() { -// return name; -// } - -// public ArgumentCommandNode build() { -// final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider()); - -// for (final CommandNode argument : getArguments()) { -// result.addChild(argument); -// } - -// return result; -// } - -pub struct RequiredArgumentBuilder { +pub struct RequiredArgumentBuilder<'a, S, T> { // private final String name; // private final ArgumentType type; // private SuggestionProvider suggestionsProvider = null; name: String, - type_: dyn ArgumentType, - suggestions_provider: Option>, + type_: &'a T, + suggestions_provider: Option<&'a dyn SuggestionProvider>, - pub base: BaseArgumentBuilder, + pub base: BaseArgumentBuilder<'a, S, T>, } -impl RequiredArgumentBuilder { - pub fn new(name: String, type_: dyn ArgumentType) -> Self { +impl<'a, S, T> RequiredArgumentBuilder<'a, S, T> { + pub fn new(name: String, type_: T) -> Self { Self { name, - type_, + type_: &type_, suggestions_provider: None, base: BaseArgumentBuilder::new(name, type_), } } - pub fn argument(name: String, type_: dyn ArgumentType) -> Self { + pub fn argument(name: String, type_: T) -> Self { Self::new(name, type_) } - pub fn suggests(mut self, provider: dyn SuggestionProvider) -> Self { + pub fn suggests(mut self, provider: &dyn SuggestionProvider) -> Self { self.suggestions_provider = Some(provider); self } - pub fn suggestions_provider(&self) -> Option<&dyn SuggestionProvider> { + pub fn suggestions_provider(&self) -> Option<&dyn SuggestionProvider> { self.suggestions_provider.as_ref() } - pub fn get_type(&self) -> &dyn ArgumentType { - &self.type_ + pub fn get_type(&self) -> &T { + self.type_ } pub fn name(&self) -> &str { - &self.name + self.name } // final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider()); @@ -96,7 +54,7 @@ impl RequiredArgumentBuilder { // } // return result; - pub fn build(self) -> ArgumentCommandNode { + pub fn build(self) -> ArgumentCommandNode<'a, S, T> { let result = ArgumentCommandNode { name: self.name, type_: &self.type_, diff --git a/azalea-brigadier/src/command.rs b/azalea-brigadier/src/command.rs index a76454b7..520c8a52 100644 --- a/azalea-brigadier/src/command.rs +++ b/azalea-brigadier/src/command.rs @@ -5,6 +5,6 @@ use crate::{ pub const SINGLE_SUCCESS: i32 = 1; -pub trait Command { - fn run(&self, context: &mut CommandContext) -> Result; +pub trait Command { + fn run(&self, context: &mut CommandContext) -> Result; } diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs index 0e9b9036..d0351547 100644 --- a/azalea-brigadier/src/command_dispatcher.rs +++ b/azalea-brigadier/src/command_dispatcher.rs @@ -2,11 +2,12 @@ use crate::tree::root_command_node::RootCommandNode; /// 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 -pub struct CommandDispatcher { - root: RootCommandNode, +#[derive(Default)] +pub struct CommandDispatcher<'a, S, T> { + root: RootCommandNode<'a, S, T>, } -impl CommandDispatcher { +impl CommandDispatcher<'_, S, T> { /// The string required to separate individual arguments in an input string /// /// See: [`ARGUMENT_SEPARATOR_CHAR`] @@ -22,4 +23,23 @@ impl CommandDispatcher { const USAGE_REQUIRED_OPEN: &'static str = "("; const USAGE_REQUIRED_CLOSE: &'static str = ")"; const USAGE_OR: &'static str = "|"; + + /// Create a new [`CommandDispatcher`] with the specified root node. + /// This is often useful to copy existing or pre-defined command trees. + /// # Example + /// ``` + /// use azalea_brigadier::{ + /// command_dispatcher::CommandDispatcher, + /// tree::root_command_node::RootCommandNode, + /// }; + /// + /// let mut dispatcher = CommandDispatcher::new(RootCommandNode::new()); + /// ``` + /// # Arguments + /// * `root` - the existing [`RootCommandNode`] to use as the basis for this tree + /// # Returns + /// A new [`CommandDispatcher`] with the specified root node. + fn new(root: RootCommandNode) -> Self { + Self { root } + } } diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index 7a2189d9..36741906 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -3,27 +3,25 @@ use super::{ string_range::StringRange, }; use crate::{ - arguments::argument_type::{ArgumentResult, ArgumentType}, - command::Command, - redirect_modifier::RedirectModifier, + arguments::argument_type::ArgumentType, command::Command, redirect_modifier::RedirectModifier, tree::command_node::CommandNode, }; use std::collections::HashMap; -pub struct CommandContext { +pub struct CommandContext<'a, S, T> { source: S, input: String, - command: dyn Command, - arguments: HashMap>>, - root_node: dyn CommandNode, - nodes: Vec>, + command: &'a dyn Command, + arguments: HashMap>, + root_node: &'a dyn CommandNode, + nodes: Vec>, range: StringRange, - child: Option>, - modifier: Option>, + child: Option>, + modifier: Option<&'a dyn RedirectModifier>, forks: bool, } -impl CommandContext { +impl CommandContext<'_, S, T> { pub fn clone_for(&self, source: S) -> Self { if self.source == source { return self.clone(); @@ -42,11 +40,11 @@ impl CommandContext { } } - fn child(&self) -> &Option> { + fn child(&self) -> &Option> { &self.child } - fn last_child(&self) -> &CommandContext { + fn last_child(&self) -> &CommandContext { let mut result = self; while result.child.is_some() { result = result.child.as_ref().unwrap(); @@ -54,7 +52,7 @@ impl CommandContext { result } - fn command(&self) -> &dyn Command { + fn command(&self) -> &dyn Command { &self.command } diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index 5766ea9a..878d7692 100644 --- a/azalea-brigadier/src/context/command_context_builder.rs +++ b/azalea-brigadier/src/context/command_context_builder.rs @@ -25,16 +25,16 @@ use super::{ // private boolean forks; #[derive(Clone)] -pub struct CommandContextBuilder { - arguments: HashMap>>, - root_node: dyn CommandNode, - nodes: Vec>, - dispatcher: CommandDispatcher, +pub struct CommandContextBuilder<'a, S, T> { + arguments: HashMap>, + root_node: &'a dyn CommandNode, + nodes: Vec>, + dispatcher: CommandDispatcher<'a, S, T>, source: S, - command: Box>, - child: Option>, + command: Box>, + child: Option>, range: StringRange, - modifier: Option>>, + modifier: Option>>, forks: bool, } @@ -45,15 +45,15 @@ pub struct CommandContextBuilder { // this.range = StringRange.at(start); // } -impl CommandContextBuilder { +impl CommandContextBuilder<'_, S, T> { pub fn new( - dispatcher: CommandDispatcher, + dispatcher: CommandDispatcher, source: S, - root_node: dyn CommandNode, + root_node: dyn CommandNode, start: usize, ) -> Self { Self { - root_node, + root_node: &root_node, dispatcher, source, range: StringRange::at(start), @@ -70,31 +70,25 @@ impl CommandContextBuilder { &self.source } - pub fn root_node(&self) -> &dyn CommandNode { + pub fn root_node(&self) -> &dyn CommandNode { &self.root_node } - pub fn with_argument( - mut self, - name: String, - argument: ParsedArgument>, - ) -> Self { + pub fn with_argument(mut self, name: String, argument: ParsedArgument) -> Self { self.arguments.insert(name, argument); self } - pub fn arguments( - &self, - ) -> &HashMap>> { + pub fn arguments(&self) -> &HashMap> { &self.arguments } - pub fn with_command(mut self, command: Box>) -> Self { + pub fn with_command(mut self, command: &dyn Command) -> Self { self.command = command; self } - pub fn with_node(mut self, node: dyn CommandNode, range: StringRange) -> Self { + pub fn with_node(mut self, node: dyn CommandNode, range: StringRange) -> Self { self.nodes.push(ParsedCommandNode::new(node, range)); self.range = StringRange::encompassing(&self.range, &range); self.modifier = node.redirect_modifier(); @@ -102,16 +96,16 @@ impl CommandContextBuilder { self } - pub fn with_child(mut self, child: CommandContextBuilder) -> Self { + pub fn with_child(mut self, child: CommandContextBuilder) -> Self { self.child = Some(child); self } - pub fn child(&self) -> Option<&CommandContextBuilder> { + pub fn child(&self) -> Option<&CommandContextBuilder> { self.child.as_ref() } - pub fn last_child(&self) -> Option<&CommandContextBuilder> { + pub fn last_child(&self) -> Option<&CommandContextBuilder> { let mut result = self; while let Some(child) = result.child() { result = child; @@ -119,15 +113,15 @@ impl CommandContextBuilder { Some(result) } - pub fn command(&self) -> &dyn Command { + pub fn command(&self) -> &dyn Command { &*self.command } - pub fn nodes(&self) -> &Vec> { + pub fn nodes(&self) -> &Vec> { &self.nodes } - pub fn build(self, input: &str) -> CommandContext { + pub fn build(self, input: &str) -> CommandContext { CommandContext { source: self.source, input, @@ -142,7 +136,7 @@ impl CommandContextBuilder { } } - pub fn dispatcher(&self) -> &CommandDispatcher { + pub fn dispatcher(&self) -> &CommandDispatcher { &self.dispatcher } @@ -150,7 +144,7 @@ impl CommandContextBuilder { &self.range } - pub fn find_suggestion_context(&self, cursor: i32) -> Result, String> { + pub fn find_suggestion_context(&self, cursor: i32) -> Result, String> { if self.range.start() <= cursor { if self.range.end() < cursor { if let Some(child) = self.child() { diff --git a/azalea-brigadier/src/context/parsed_argument.rs b/azalea-brigadier/src/context/parsed_argument.rs index 77a47078..75c07784 100644 --- a/azalea-brigadier/src/context/parsed_argument.rs +++ b/azalea-brigadier/src/context/parsed_argument.rs @@ -1,10 +1,9 @@ -use std::marker::PhantomData; - use super::string_range::StringRange; #[derive(PartialEq, Eq, Hash)] pub struct ParsedArgument { range: StringRange, + // T is an item in an enum result: T, } diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs index 98e99959..a006aa4b 100644 --- a/azalea-brigadier/src/context/parsed_command_node.rs +++ b/azalea-brigadier/src/context/parsed_command_node.rs @@ -2,17 +2,17 @@ use super::string_range::StringRange; use crate::tree::command_node::CommandNode; #[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct ParsedCommandNode { - node: dyn CommandNode, +pub struct ParsedCommandNode<'a, S, T> { + node: &'a dyn CommandNode, range: StringRange, } -impl ParsedCommandNode { - fn new(node: dyn CommandNode, range: StringRange) -> Self { +impl ParsedCommandNode<'_, S, T> { + fn new(node: &dyn CommandNode, range: StringRange) -> Self { Self { node, range } } - fn node(&self) -> &dyn CommandNode { + fn node(&self) -> &dyn CommandNode { &self.node } diff --git a/azalea-brigadier/src/context/suggestion_context.rs b/azalea-brigadier/src/context/suggestion_context.rs index 540a5f23..42bc550e 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; -pub struct SuggestionContext { - parent: dyn CommandNode, +pub struct SuggestionContext<'a, S, T> { + parent: &'a dyn CommandNode, start_pos: usize, } diff --git a/azalea-brigadier/src/redirect_modifier.rs b/azalea-brigadier/src/redirect_modifier.rs index cfefd120..fd2e1bf7 100644 --- a/azalea-brigadier/src/redirect_modifier.rs +++ b/azalea-brigadier/src/redirect_modifier.rs @@ -3,6 +3,6 @@ use crate::{ exceptions::command_syntax_exception::CommandSyntaxException, }; -pub trait RedirectModifier { - fn apply(&self, context: CommandContext) -> Result, CommandSyntaxException>; +pub trait RedirectModifier { + fn apply(&self, context: CommandContext) -> Result, CommandSyntaxException>; } diff --git a/azalea-brigadier/src/single_redirect_modifier.rs b/azalea-brigadier/src/single_redirect_modifier.rs index dd63244d..95055fd8 100644 --- a/azalea-brigadier/src/single_redirect_modifier.rs +++ b/azalea-brigadier/src/single_redirect_modifier.rs @@ -3,6 +3,6 @@ use crate::{ exceptions::command_syntax_exception::CommandSyntaxException, }; -pub trait SingleRedirectModifier { - fn apply(&self, context: CommandContext) -> Result; +pub trait SingleRedirectModifier { + fn apply(&self, context: CommandContext) -> Result; } diff --git a/azalea-brigadier/src/suggestion/suggestion_provider.rs b/azalea-brigadier/src/suggestion/suggestion_provider.rs index 3027d460..9720d3b9 100644 --- a/azalea-brigadier/src/suggestion/suggestion_provider.rs +++ b/azalea-brigadier/src/suggestion/suggestion_provider.rs @@ -5,10 +5,10 @@ use crate::{ use super::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder}; -pub trait SuggestionProvider { +pub trait SuggestionProvider { fn suggestions( &self, - context: &CommandContext, + context: &CommandContext, builder: &SuggestionsBuilder, ) -> Result; } diff --git a/azalea-brigadier/src/tree/argument_command_node.rs b/azalea-brigadier/src/tree/argument_command_node.rs index 51add3d5..4d38b41f 100644 --- a/azalea-brigadier/src/tree/argument_command_node.rs +++ b/azalea-brigadier/src/tree/argument_command_node.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Formatter}; use crate::{ - arguments::argument_type::{ArgumentResult, ArgumentType}, + arguments::argument_type::ArgumentType, builder::required_argument_builder::RequiredArgumentBuilder, context::{ command_context::CommandContext, command_context_builder::CommandContextBuilder, @@ -21,25 +21,25 @@ const USAGE_ARGUMENT_OPEN: &str = "<"; const USAGE_ARGUMENT_CLOSE: &str = ">"; #[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct ArgumentCommandNode { +pub struct ArgumentCommandNode<'a, S, T> { name: String, - type_: Box>, - custom_suggestions: dyn SuggestionProvider, + type_: &'a T, + 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, + pub base: BaseCommandNode<'a, S, T>, } -impl ArgumentCommandNode { - fn get_type(&self) -> &dyn ArgumentType { +impl ArgumentCommandNode<'_, S, T> { + fn get_type(&self) -> &T { &self.type_ } - fn custom_suggestions(&self) -> &dyn SuggestionProvider { + fn custom_suggestions(&self) -> &dyn SuggestionProvider { &self.custom_suggestions } } -impl CommandNode for ArgumentCommandNode { +impl CommandNode for ArgumentCommandNode<'_, S, T> { fn name(&self) -> &str { &self.name } @@ -47,7 +47,7 @@ impl CommandNode for ArgumentCommandNode { fn parse( &self, reader: &mut StringReader, - context_builder: CommandContextBuilder, + context_builder: CommandContextBuilder, ) -> Result<(), CommandSyntaxException> { // final int start = reader.getCursor(); // final T result = type.parse(reader); @@ -68,7 +68,7 @@ impl CommandNode for ArgumentCommandNode { fn list_suggestions( &self, - context: CommandContext, + context: CommandContext, builder: &mut SuggestionsBuilder, ) -> Result { if self.custom_suggestions.is_none() { @@ -112,7 +112,7 @@ impl CommandNode for ArgumentCommandNode { } } -impl Display for ArgumentCommandNode { +impl Display for ArgumentCommandNode<'_, String, String> { 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 0d9212aa..bcba9c03 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - arguments::argument_type::{ArgumentResult, ArgumentType}, + arguments::argument_type::ArgumentType, builder::argument_builder::ArgumentBuilder, command::Command, context::{command_context::CommandContext, command_context_builder::CommandContextBuilder}, @@ -13,33 +13,33 @@ use crate::{ use super::{argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode}; -pub struct BaseCommandNode { - children: HashMap>, - literals: HashMap>, - arguments: HashMap>>, - requirement: Option bool>, - redirect: Option>, - modifier: Option>, +pub struct BaseCommandNode<'a, S, T> { + children: HashMap>, + literals: HashMap>, + arguments: HashMap>, + requirement: Option<&'a dyn Fn(&S) -> bool>, + redirect: Option<&'a dyn CommandNode>, + modifier: Option<&'a dyn RedirectModifier>, forks: bool, - command: Option>, + command: Option<&'a dyn Command>, } -impl BaseCommandNode {} +impl BaseCommandNode<'_, S, T> {} -pub trait CommandNode { +pub trait CommandNode { fn name(&self) -> &str; fn usage_text(&self) -> &str; fn parse( &self, reader: StringReader, - context_builder: CommandContextBuilder, + context_builder: CommandContextBuilder, ) -> Result<(), CommandSyntaxException>; fn list_suggestions( &self, - context: CommandContext, + context: CommandContext, builder: SuggestionsBuilder, ) -> Result; fn is_valid_input(&self, input: &str) -> bool; - fn create_builder(&self) -> dyn ArgumentBuilder; + fn create_builder(&self) -> dyn ArgumentBuilder; fn get_examples(&self) -> Vec; } diff --git a/azalea-brigadier/src/tree/literal_command_node.rs b/azalea-brigadier/src/tree/literal_command_node.rs index bb0e613c..fe933669 100644 --- a/azalea-brigadier/src/tree/literal_command_node.rs +++ b/azalea-brigadier/src/tree/literal_command_node.rs @@ -1,8 +1,11 @@ use crate::{ + builder::literal_argument_builder::LiteralArgumentBuilder, + command::Command, 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}, }; @@ -10,14 +13,23 @@ use crate::{ use super::command_node::{BaseCommandNode, CommandNode}; #[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct LiteralCommandNode { +pub struct LiteralCommandNode<'a, S, T> { 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, + pub base: BaseCommandNode<'a, S, T>, } -impl LiteralCommandNode { +impl<'a, S, T> LiteralCommandNode<'a, S, T> { + pub fn new(literal: String, base: BaseCommandNode) -> Self { + let literal_lowercase = literal.to_lowercase(); + Self { + literal, + literal_lowercase, + base, + } + } + pub fn literal(&self) -> &String { &self.literal } @@ -39,7 +51,7 @@ impl LiteralCommandNode { } } -impl CommandNode for LiteralCommandNode { +impl CommandNode for LiteralCommandNode<'_, S, T> { fn name(&self) -> &str { &self.literal } @@ -47,7 +59,7 @@ impl CommandNode for LiteralCommandNode { fn parse( &self, reader: StringReader, - context_builder: CommandContextBuilder, + context_builder: CommandContextBuilder, ) -> Result<(), CommandSyntaxException> { let start = reader.get_cursor(); let end = self.parse(reader); @@ -63,7 +75,7 @@ impl CommandNode for LiteralCommandNode { fn list_suggestions( &self, - context: CommandContext, + context: CommandContext, builder: SuggestionsBuilder, ) -> Result { if self @@ -84,7 +96,7 @@ impl CommandNode for LiteralCommandNode { self.literal } - fn create_builder(&self) -> LiteralArgumentBuilder { + fn create_builder(&self) -> LiteralArgumentBuilder { let builder = LiteralArgumentBuilder::literal(self.literal()); builder.requires(self.requirement()); builder.forward(self.redirect(), self.redirect_modifier(), self.is_fork()); diff --git a/azalea-brigadier/src/tree/root_command_node.rs b/azalea-brigadier/src/tree/root_command_node.rs index 004ab6a8..25a5a4b2 100644 --- a/azalea-brigadier/src/tree/root_command_node.rs +++ b/azalea-brigadier/src/tree/root_command_node.rs @@ -12,12 +12,12 @@ use crate::{ use super::command_node::{BaseCommandNode, CommandNode}; #[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct RootCommandNode { +pub struct RootCommandNode<'a, S, T> { // Since Rust doesn't have extending, we put the struct this is extending as the "base" field - pub base: BaseCommandNode, + pub base: BaseCommandNode<'a, S, T>, } -impl CommandNode for RootCommandNode { +impl CommandNode for RootCommandNode<'_, S, T> { fn name(&self) -> &str { "" } @@ -25,13 +25,13 @@ impl CommandNode for RootCommandNode { fn parse( &self, reader: StringReader, - context_builder: CommandContextBuilder, + context_builder: CommandContextBuilder, ) -> Result<(), CommandSyntaxException> { } fn list_suggestions( &self, - context: CommandContext, + context: CommandContext, builder: SuggestionsBuilder, ) -> Result { Suggestions::empty() @@ -54,7 +54,7 @@ impl CommandNode for RootCommandNode { } } -impl Display for RootCommandNode<()> { +impl Display for RootCommandNode<'_, S, T> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "") }