From 760816c81fab414cc42ab1e75506fc816bcf9681 Mon Sep 17 00:00:00 2001 From: mat Date: Thu, 13 Jan 2022 20:08:53 -0600 Subject: [PATCH] stuff --- .../src/arguments/argument_type.rs | 7 +- .../src/builder/argument_builder.rs | 44 +++++-- .../src/builder/literal_argument_builder.rs | 14 ++- .../src/builder/required_argument_builder.rs | 4 +- .../src/tree/argument_command_node.rs | 6 +- 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( &self, context: &CommandContext, - builder: &mut SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result 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>, - requirement: &'a dyn Fn(&S) -> bool, - target: Option<&'a dyn CommandNode>, - modifier: Option<&'a dyn RedirectModifier>, + command: Option>>, + requirement: Box bool>, + target: Option>>, + modifier: Option>>, forks: bool, } @@ -22,15 +25,18 @@ pub trait ArgumentBuilder where T: ArgumentBuilder, { - fn build(self) -> dyn CommandNode; + fn build(self) -> Box>; } -impl BaseArgumentBuilder<'_, S> { - pub fn then(&mut self, command: dyn CommandNode) -> Result<&mut Self, String> { +impl<'a, S> BaseArgumentBuilder<'a, S> { + pub fn then( + &mut self, + command: Box>, + ) -> 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 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 for LiteralArgumentBuilder<'a, S> +where + T: ArgumentBuilder, +{ + fn build(self) -> Box> { + 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) -> Self { + pub fn new(name: String, type_: Box>) -> 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, - builder: &mut SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result { if self.custom_suggestions.is_none() { self.get_type().list_suggestions(context, builder) @@ -118,6 +118,10 @@ where fn get_examples(&self) -> Vec { self.type_.get_examples() } + + fn base(&self) -> &BaseCommandNode { + &self.base + } } impl 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>, + children: HashMap>>, literals: HashMap>, arguments: HashMap>, - requirement: Option<&'a dyn Fn(&S) -> bool>, - redirect: Option<&'a dyn CommandNode>, - modifier: Option<&'a dyn RedirectModifier>, + requirement: Box bool>, + redirect: Option>>, + modifier: Option>>, forks: bool, - command: Option<&'a dyn Command>, + command: Option>>, } -impl BaseCommandNode<'_, S> {} +impl BaseCommandNode<'_, S> { + pub fn command(&self) -> &Option>> { + &self.command + } + + pub fn children(&self) -> &HashMap>> { + &self.children + } + + pub fn child(&self, name: &str) -> Option<&dyn CommandNode> { + self.children.get(name).map(|child| child.as_ref()) + } + + pub fn redirect(&self) -> Option<&dyn CommandNode> { + self.redirect.as_ref().map(|redirect| redirect.as_ref()) + } + + pub fn redirect_modifier(&self) -> Option<&dyn RedirectModifier> { + 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 node) { + // if (node instanceof RootCommandNode) { + // throw new UnsupportedOperationException("Cannot add a RootCommandNode as a child to any other CommandNode"); + // } + + // final CommandNode 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 grandchild : node.getChildren()) { + // child.addChild(grandchild); + // } + // } else { + // children.put(node.getName(), node); + // if (node instanceof LiteralCommandNode) { + // literals.put(node.getName(), (LiteralCommandNode) node); + // } else if (node instanceof ArgumentCommandNode) { + // arguments.put(node.getName(), (ArgumentCommandNode) node); + // } + // } + // } + + pub fn add_child(&self, node: &dyn CommandNode) -> Result<(), String> { + if (&node as &dyn Any).is::>() { + 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 + { + 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 + { + self.arguments + .insert(node.name().to_string(), argument.clone_boxed()); + } + } + } +} impl Clone for BaseCommandNode<'_, S> { fn clone(&self) -> Self { @@ -56,8 +138,22 @@ impl Debug for BaseCommandNode<'_, S> { } } -#[clonable] -pub trait CommandNode: Clone { +impl 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 { fn name(&self) -> &str; fn usage_text(&self) -> &str; fn parse( @@ -68,9 +164,10 @@ pub trait CommandNode: Clone { fn list_suggestions( &self, context: CommandContext, - builder: SuggestionsBuilder, + builder: &SuggestionsBuilder, ) -> Result; fn is_valid_input(&self, input: &str) -> bool; fn create_builder(&self) -> dyn ArgumentBuilder; fn get_examples(&self) -> Vec; + fn base(&self) -> &BaseCommandNode; }