This commit is contained in:
mat 2022-01-13 20:08:53 -06:00
parent eb111be1f1
commit 760816c81f
6 changed files with 164 additions and 30 deletions

View file

@ -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,

View file

@ -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
}
}

View file

@ -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);

View file

@ -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_),
}

View file

@ -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> {

View file

@ -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>;
}