diff options
| author | mat <github@matdoes.dev> | 2022-01-13 20:08:53 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-01-13 20:08:53 -0600 |
| commit | 760816c81fab414cc42ab1e75506fc816bcf9681 (patch) | |
| tree | e5a52f4f90969ed06db0b81a0fe37e7a94fdca53 | |
| parent | eb111be1f107696939b994f5de6e060cf972a732 (diff) | |
| download | azalea-drasl-760816c81fab414cc42ab1e75506fc816bcf9681.tar.xz | |
stuff
| -rw-r--r-- | azalea-brigadier/src/arguments/argument_type.rs | 7 | ||||
| -rw-r--r-- | azalea-brigadier/src/builder/argument_builder.rs | 44 | ||||
| -rw-r--r-- | azalea-brigadier/src/builder/literal_argument_builder.rs | 14 | ||||
| -rw-r--r-- | azalea-brigadier/src/builder/required_argument_builder.rs | 4 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/argument_command_node.rs | 6 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/command_node.rs | 119 |
6 files changed, 164 insertions, 30 deletions
diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs index 3d1b1168..37cc9354 100644 --- a/azalea-brigadier/src/arguments/argument_type.rs +++ b/azalea-brigadier/src/arguments/argument_type.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use super::bool_argument_type::BoolArgumentType; use crate::{ context::command_context::CommandContext, @@ -31,8 +33,7 @@ impl Types for BrigadierTypes { } */ -#[clonable] -pub trait ArgumentType: Clone { +pub trait ArgumentType { type Into; // T parse(StringReader reader) throws CommandSyntaxException; @@ -49,7 +50,7 @@ pub trait ArgumentType: Clone { fn list_suggestions<S>( &self, context: &CommandContext<S>, - builder: &mut SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException> where Self: Sized, diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index 6355456a..8c30bd44 100644 --- a/azalea-brigadier/src/builder/argument_builder.rs +++ b/azalea-brigadier/src/builder/argument_builder.rs @@ -3,7 +3,10 @@ use crate::{ command::Command, redirect_modifier::RedirectModifier, single_redirect_modifier::SingleRedirectModifier, - tree::{command_node::CommandNode, root_command_node::RootCommandNode}, + tree::{ + command_node::{BaseCommandNode, CommandNode}, + root_command_node::RootCommandNode, + }, }; pub struct BaseArgumentBuilder<'a, S> @@ -11,10 +14,10 @@ where S: Sized, { arguments: RootCommandNode<'a, S>, - command: Option<&'a dyn Command<S>>, - requirement: &'a dyn Fn(&S) -> bool, - target: Option<&'a dyn CommandNode<S>>, - modifier: Option<&'a dyn RedirectModifier<S>>, + command: Option<Box<dyn Command<S>>>, + requirement: Box<dyn Fn(&S) -> bool>, + target: Option<Box<dyn CommandNode<S>>>, + modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, } @@ -22,15 +25,18 @@ pub trait ArgumentBuilder<S, T> where T: ArgumentBuilder<S, T>, { - fn build(self) -> dyn CommandNode<S>; + fn build(self) -> Box<dyn CommandNode<S>>; } -impl<S> BaseArgumentBuilder<'_, S> { - pub fn then(&mut self, command: dyn CommandNode<S>) -> Result<&mut Self, String> { +impl<'a, S> BaseArgumentBuilder<'a, S> { + pub fn then( + &mut self, + command: Box<dyn ArgumentBuilder<S, Self>>, + ) -> Result<&mut Self, String> { if self.target.is_some() { return Err("Cannot add children to a redirected node".to_string()); } - self.command = command; + self.command = Some(command); Ok(self) } @@ -103,4 +109,24 @@ impl<S> BaseArgumentBuilder<'_, S> { pub fn is_fork(&self) -> bool { self.forks } + + pub fn build(self) -> BaseCommandNode<'a, S> { + let result: BaseCommandNode<'a, S> = BaseCommandNode { + command: self.command, + requirement: self.requirement, + redirect: self.target, + modifier: self.modifier, + forks: self.forks, + + arguments: Default::default(), + children: Default::default(), + literals: Default::default(), + }; + + for argument in self.arguments() { + result.add_child(argument); + } + + result + } } diff --git a/azalea-brigadier/src/builder/literal_argument_builder.rs b/azalea-brigadier/src/builder/literal_argument_builder.rs index 8039dff0..0bd6071c 100644 --- a/azalea-brigadier/src/builder/literal_argument_builder.rs +++ b/azalea-brigadier/src/builder/literal_argument_builder.rs @@ -1,8 +1,9 @@ use crate::{ - arguments::argument_type::ArgumentType, tree::literal_command_node::LiteralCommandNode, + arguments::argument_type::ArgumentType, + tree::{command_node::CommandNode, literal_command_node::LiteralCommandNode}, }; -use super::argument_builder::BaseArgumentBuilder; +use super::argument_builder::{ArgumentBuilder, BaseArgumentBuilder}; pub struct LiteralArgumentBuilder<'a, S> { literal: String, @@ -21,9 +22,14 @@ impl<'a, S> LiteralArgumentBuilder<'a, S> { pub fn literal(name: String) -> Self { Self::new(name) } +} - pub fn build(self) -> LiteralCommandNode<'a, S> { - let result = LiteralCommandNode::new(self.literal, self.base); +impl<'a, S, T> ArgumentBuilder<S, T> for LiteralArgumentBuilder<'a, S> +where + T: ArgumentBuilder<S, T>, +{ + fn build(self) -> Box<dyn CommandNode<S>> { + let result = LiteralCommandNode::new(self.literal, self.base.build()); for argument in self.base.arguments { result.add_child(argument); diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index 29af7f6f..b69c9dab 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -19,10 +19,10 @@ pub struct RequiredArgumentBuilder<'a, S> { } impl<'a, S> RequiredArgumentBuilder<'a, S> { - pub fn new(name: String, type_: dyn ArgumentType<Into = dyn Any>) -> Self { + pub fn new(name: String, type_: Box<dyn ArgumentType<Into = dyn Any>>) -> Self { Self { name, - type_: &type_, + type_: type_, suggestions_provider: None, base: BaseArgumentBuilder::new(name, type_), } diff --git a/azalea-brigadier/src/tree/argument_command_node.rs b/azalea-brigadier/src/tree/argument_command_node.rs index fb9a75fa..e33c3d3e 100644 --- a/azalea-brigadier/src/tree/argument_command_node.rs +++ b/azalea-brigadier/src/tree/argument_command_node.rs @@ -77,7 +77,7 @@ where fn list_suggestions( &self, context: CommandContext<S>, - builder: &mut SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException> { if self.custom_suggestions.is_none() { self.get_type().list_suggestions(context, builder) @@ -118,6 +118,10 @@ where fn get_examples(&self) -> Vec<String> { self.type_.get_examples() } + + fn base(&self) -> &BaseCommandNode<S> { + &self.base + } } impl<S> Display for ArgumentCommandNode<'_, S> { diff --git a/azalea-brigadier/src/tree/command_node.rs b/azalea-brigadier/src/tree/command_node.rs index b8f416eb..f59b1cef 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -1,4 +1,7 @@ -use super::{argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode}; +use super::{ + argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode, + root_command_node::RootCommandNode, +}; use crate::{ arguments::argument_type::ArgumentType, builder::argument_builder::ArgumentBuilder, @@ -12,19 +15,98 @@ use crate::{ use dyn_clonable::*; use std::{any::Any, collections::HashMap, fmt::Debug}; -#[derive(Default)] pub struct BaseCommandNode<'a, S> { - children: HashMap<String, &'a dyn CommandNode<S>>, + children: HashMap<String, Box<dyn CommandNode<S>>>, literals: HashMap<String, LiteralCommandNode<'a, S>>, arguments: HashMap<String, ArgumentCommandNode<'a, S>>, - requirement: Option<&'a dyn Fn(&S) -> bool>, - redirect: Option<&'a dyn CommandNode<S>>, - modifier: Option<&'a dyn RedirectModifier<S>>, + requirement: Box<dyn Fn(&S) -> bool>, + redirect: Option<Box<dyn CommandNode<S>>>, + modifier: Option<Box<dyn RedirectModifier<S>>>, forks: bool, - command: Option<&'a dyn Command<S>>, + command: Option<Box<dyn Command<S>>>, } -impl<S> BaseCommandNode<'_, S> {} +impl<S> BaseCommandNode<'_, S> { + pub fn command(&self) -> &Option<Box<dyn Command<S>>> { + &self.command + } + + pub fn children(&self) -> &HashMap<String, Box<dyn CommandNode<S>>> { + &self.children + } + + pub fn child(&self, name: &str) -> Option<&dyn CommandNode<S>> { + self.children.get(name).map(|child| child.as_ref()) + } + + pub fn redirect(&self) -> Option<&dyn CommandNode<S>> { + self.redirect.as_ref().map(|redirect| redirect.as_ref()) + } + + pub fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> { + self.modifier.as_ref().map(|modifier| modifier.as_ref()) + } + + pub fn can_use(&self, source: S) -> bool { + (self.requirement)(&source) + } + + // public void addChild(final CommandNode<S> node) { + // if (node instanceof RootCommandNode) { + // throw new UnsupportedOperationException("Cannot add a RootCommandNode as a child to any other CommandNode"); + // } + + // final CommandNode<S> child = children.get(node.getName()); + // if (child != null) { + // // We've found something to merge onto + // if (node.getCommand() != null) { + // child.command = node.getCommand(); + // } + // for (final CommandNode<S> grandchild : node.getChildren()) { + // child.addChild(grandchild); + // } + // } else { + // children.put(node.getName(), node); + // if (node instanceof LiteralCommandNode) { + // literals.put(node.getName(), (LiteralCommandNode<S>) node); + // } else if (node instanceof ArgumentCommandNode) { + // arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node); + // } + // } + // } + + pub fn add_child(&self, node: &dyn CommandNode<S>) -> Result<(), String> { + if (&node as &dyn Any).is::<RootCommandNode<S>>() { + return Err(String::from( + "Cannot add a RootCommandNode as a child to any other CommandNode", + )); + } + + let child = self.children.get(node.name()); + if let Some(child) = child { + // We've found something to merge onto + if let Some(command) = node.base.command() { + child.command = Some(command); + } + for grandchild in node.children() { + child.add_child(grandchild)?; + } + } else { + self.children.insert(node.name().to_string(), node); + if let Some(literal) = + &node.clone_boxed() as &dyn Any as &dyn Any as &LiteralCommandNode<S> + { + self.literals + .insert(node.name().to_string(), literal.clone_boxed()); + } else if let Some(argument) = + &node.clone_boxed() as &dyn Any as &dyn Any as &ArgumentCommandNode<S> + { + self.arguments + .insert(node.name().to_string(), argument.clone_boxed()); + } + } + } +} impl<S> Clone for BaseCommandNode<'_, S> { fn clone(&self) -> Self { @@ -56,8 +138,22 @@ impl<S> Debug for BaseCommandNode<'_, S> { } } -#[clonable] -pub trait CommandNode<S>: Clone { +impl<S> Default for BaseCommandNode<'_, S> { + fn default() -> Self { + Self { + children: HashMap::new(), + literals: HashMap::new(), + arguments: HashMap::new(), + requirement: Box::new(|_| true), + redirect: None, + modifier: None, + forks: false, + command: None, + } + } +} + +pub trait CommandNode<S> { fn name(&self) -> &str; fn usage_text(&self) -> &str; fn parse( @@ -68,9 +164,10 @@ pub trait CommandNode<S>: Clone { fn list_suggestions( &self, context: CommandContext<S>, - builder: SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result<Suggestions, CommandSyntaxException>; fn is_valid_input(&self, input: &str) -> bool; fn create_builder(&self) -> dyn ArgumentBuilder<S, dyn Any>; fn get_examples(&self) -> Vec<String>; + fn base(&self) -> &BaseCommandNode<S>; } |
