aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-01-13 20:08:53 -0600
committermat <github@matdoes.dev>2022-01-13 20:08:53 -0600
commit760816c81fab414cc42ab1e75506fc816bcf9681 (patch)
treee5a52f4f90969ed06db0b81a0fe37e7a94fdca53
parenteb111be1f107696939b994f5de6e060cf972a732 (diff)
downloadazalea-drasl-760816c81fab414cc42ab1e75506fc816bcf9681.tar.xz
stuff
-rw-r--r--azalea-brigadier/src/arguments/argument_type.rs7
-rw-r--r--azalea-brigadier/src/builder/argument_builder.rs44
-rw-r--r--azalea-brigadier/src/builder/literal_argument_builder.rs14
-rw-r--r--azalea-brigadier/src/builder/required_argument_builder.rs4
-rw-r--r--azalea-brigadier/src/tree/argument_command_node.rs6
-rw-r--r--azalea-brigadier/src/tree/command_node.rs119
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>;
}