This commit is contained in:
mat 2022-02-03 02:16:24 +00:00
parent 1b88888151
commit 4ff67d4917
9 changed files with 91 additions and 84 deletions

19
Cargo.lock generated
View file

@ -72,6 +72,7 @@ name = "azalea-brigadier"
version = "0.1.0"
dependencies = [
"dyn-clonable",
"enum_dispatch",
"lazy_static",
]
@ -382,6 +383,18 @@ dependencies = [
"syn",
]
[[package]]
name = "enum_dispatch"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "flate2"
version = "1.0.22"
@ -717,6 +730,12 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "oorandom"
version = "11.1.3"

View file

@ -8,3 +8,4 @@ version = "0.1.0"
[dependencies]
lazy_static = "^1.4"
dyn-clonable = "^0.9"
enum_dispatch = "^0.3"

View file

@ -10,11 +10,8 @@ use crate::{
};
use std::fmt::Debug;
pub struct LiteralArgumentBuilder<'a, S>
where
,
{
arguments: RootCommandNode<'a, S>,
pub struct LiteralArgumentBuilder<S> {
arguments: RootCommandNode<S>,
command: Option<Box<dyn Command<S>>>,
requirement: Box<dyn Fn(&S) -> bool>,
target: Option<Box<dyn CommandNodeTrait<S>>>,
@ -23,10 +20,7 @@ where
literal: String,
}
impl<'a, S> LiteralArgumentBuilder<'a, S>
where
,
{
impl<S> LiteralArgumentBuilder<S> {
pub fn new(literal: String) -> Self {
Self {
literal,
@ -44,10 +38,7 @@ where
}
}
impl<'a, S> ArgumentBuilder<S> for LiteralArgumentBuilder<'a, S>
where
,
{
impl<S> ArgumentBuilder<S> for LiteralArgumentBuilder<S> {
fn build(self) -> Box<dyn CommandNodeTrait<S>> {
let result = LiteralCommandNode::new(self.literal, self.base.build());

View file

@ -4,11 +4,11 @@ use std::fmt::Debug;
/// 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
#[derive(Default, Clone)]
pub struct CommandDispatcher<'a, S> {
root: RootCommandNode<'a, S>,
pub struct CommandDispatcher<S> {
root: RootCommandNode<S>,
}
impl<S> CommandDispatcher<'_, S> {
impl<S> CommandDispatcher<S> {
/// The string required to separate individual arguments in an input string
///
/// See: [`ARGUMENT_SEPARATOR_CHAR`]

View file

@ -1,6 +1,9 @@
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate enum_dispatch;
mod ambiguity_consumer;
mod arguments;
mod builder;

View file

@ -31,18 +31,14 @@ use super::{
const USAGE_ARGUMENT_OPEN: &str = "<";
const USAGE_ARGUMENT_CLOSE: &str = ">";
#[derive(Clone, Debug)]
pub struct ArgumentCommandNode<'a, S> {
pub struct ArgumentCommandNode<S> {
name: String,
type_: Box<dyn ArgumentType<Into = dyn Any>>,
custom_suggestions: Option<&'a dyn SuggestionProvider<S>>,
// custom_suggestions: &'a dyn SuggestionProvider<S>,
// Since Rust doesn't have extending, we put the struct this is extending as the "base" field
pub base: BaseCommandNode<'a, S>,
custom_suggestions: Option<Box<dyn SuggestionProvider<S>>>,
children: HashMap<String, Box<dyn CommandNodeTrait<S>>>,
literals: HashMap<String, LiteralCommandNode<'a, S>>,
arguments: HashMap<String, ArgumentCommandNode<'a, S>>,
literals: HashMap<String, LiteralCommandNode<S>>,
arguments: HashMap<String, ArgumentCommandNode<S>>,
pub requirement: Box<dyn Fn(&S) -> bool>,
redirect: Option<Box<dyn CommandNodeTrait<S>>>,
modifier: Option<Box<dyn RedirectModifier<S>>>,
@ -50,17 +46,17 @@ pub struct ArgumentCommandNode<'a, S> {
pub command: Option<Box<dyn Command<S>>>,
}
impl<S> ArgumentCommandNode<'_, S> {
impl<S> ArgumentCommandNode<S> {
fn get_type(&self) -> &dyn ArgumentType<Into = dyn Any> {
self.type_
&*self.type_
}
fn custom_suggestions(&self) -> Option<&dyn SuggestionProvider<S>> {
self.custom_suggestions
fn custom_suggestions(&self) -> &Option<Box<dyn SuggestionProvider<S>>> {
&self.custom_suggestions
}
}
impl<'a, S> CommandNodeTrait<S> for ArgumentCommandNode<'a, S> {
impl<S> CommandNodeTrait<S> for ArgumentCommandNode<S> {
fn name(&self) -> &str {
&self.name
}
@ -173,7 +169,7 @@ impl<'a, S> CommandNodeTrait<S> for ArgumentCommandNode<'a, S> {
}
}
impl<S> Display for ArgumentCommandNode<'_, S> {
impl<S> Display for ArgumentCommandNode<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "<argument {}: {}>", self.name, self.type_)
}

View file

@ -15,43 +15,14 @@ use crate::{
use std::ops::Deref;
use std::{any::Any, collections::HashMap, fmt::Debug};
enum CommandNodeEnum<'a, S> {
Literal(LiteralCommandNode<'a, S>),
Argument(ArgumentCommandNode<'a, S>),
Root(RootCommandNode<'a, S>),
#[enum_dispatch(CommandNodeTrait)]
enum CommandNodeEnum<S> {
Literal(LiteralCommandNode<S>),
Argument(ArgumentCommandNode<S>),
Root(RootCommandNode<S>),
}
impl<'a, S> Deref for CommandNodeEnum<'a, S> {
type Target = dyn CommandNodeTrait<S>;
fn deref(&self) -> &Self::Target {
match self {
CommandNodeEnum::Literal(node) => *node as &Self::Target,
CommandNodeEnum::Argument(node) => *node as &Self::Target,
CommandNodeEnum::Root(node) => *node as &Self::Target,
}
}
}
impl<S> From<LiteralCommandNode<'_, S>> for CommandNodeEnum<'_, S> {
fn from(node: LiteralCommandNode<'_, S>) -> Self {
CommandNodeEnum::Literal(node)
}
}
impl<S> From<ArgumentCommandNode<'_, S>> for CommandNodeEnum<'_, S> {
fn from(node: ArgumentCommandNode<'_, S>) -> Self {
CommandNodeEnum::Argument(node)
}
}
impl<S> From<RootCommandNode<'_, S>> for CommandNodeEnum<'_, S> {
fn from(node: RootCommandNode<'_, S>) -> Self {
CommandNodeEnum::Root(node)
}
}
impl<S> CommandNodeEnum<'_, S> {
impl<S> CommandNodeEnum<S> {
fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> {
(*self).modifier.as_ref().map(|modifier| modifier.as_ref())
}
@ -92,10 +63,10 @@ impl<S> CommandNodeEnum<'_, S> {
}
}
}
pub struct BaseCommandNode<'a, S> {
pub struct BaseCommandNode<S> {
children: HashMap<String, Box<dyn CommandNodeTrait<S>>>,
literals: HashMap<String, LiteralCommandNode<'a, S>>,
arguments: HashMap<String, ArgumentCommandNode<'a, S>>,
literals: HashMap<String, LiteralCommandNode<S>>,
arguments: HashMap<String, ArgumentCommandNode<S>>,
pub requirement: Box<dyn Fn(&S) -> bool>,
redirect: Option<Box<dyn CommandNodeTrait<S>>>,
modifier: Option<Box<dyn RedirectModifier<S>>>,
@ -118,7 +89,7 @@ pub struct BaseCommandNode<'a, S> {
// }
// }
impl<S> Debug for BaseCommandNode<'_, S> {
impl<S> Debug for BaseCommandNode<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BaseCommandNode")
.field("children", &self.children)
@ -133,7 +104,7 @@ impl<S> Debug for BaseCommandNode<'_, S> {
}
}
impl<S> Default for BaseCommandNode<'_, S> {
impl<S> Default for BaseCommandNode<S> {
fn default() -> Self {
Self {
children: HashMap::new(),
@ -148,6 +119,7 @@ impl<S> Default for BaseCommandNode<'_, S> {
}
}
#[enum_dispatch]
pub trait CommandNodeTrait<S> {
fn name(&self) -> &str;
fn usage_text(&self) -> &str;
@ -164,4 +136,8 @@ pub trait CommandNodeTrait<S> {
fn is_valid_input(&self, input: &str) -> bool;
fn create_builder(&self) -> Box<dyn ArgumentBuilder<S>>;
fn get_examples(&self) -> Vec<String>;
fn redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>>;
fn can_use(&self, source: S) -> bool;
fn add_child(&self, node: &Box<dyn CommandNodeTrait<S>>) -> Result<(), String>;
}

View file

@ -3,33 +3,45 @@ use crate::{
builder::{
argument_builder::ArgumentBuilder, literal_argument_builder::LiteralArgumentBuilder,
},
command::Command,
context::{command_context::CommandContext, command_context_builder::CommandContextBuilder},
exceptions::{
builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
},
immutable_string_reader::ImmutableStringReader,
redirect_modifier::RedirectModifier,
string_reader::StringReader,
suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder},
};
use std::fmt::Debug;
use std::{collections::HashMap, fmt::Debug};
use super::command_node::{BaseCommandNode, CommandNodeTrait};
use super::{
argument_command_node::ArgumentCommandNode,
command_node::{BaseCommandNode, CommandNodeTrait},
};
#[derive(Debug, Clone)]
pub struct LiteralCommandNode<'a, S> {
pub struct LiteralCommandNode<S> {
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<'a, S>,
children: HashMap<String, Box<dyn CommandNodeTrait<S>>>,
literals: HashMap<String, LiteralCommandNode<S>>,
arguments: HashMap<String, ArgumentCommandNode<S>>,
pub requirement: Box<dyn Fn(&S) -> bool>,
redirect: Option<Box<dyn CommandNodeTrait<S>>>,
modifier: Option<Box<dyn RedirectModifier<S>>>,
forks: bool,
pub command: Option<Box<dyn Command<S>>>,
}
impl<'a, S> LiteralCommandNode<'a, S> {
pub fn new(literal: String, base: BaseCommandNode<'a, S>) -> Self {
impl<S> LiteralCommandNode<S> {
pub fn new(literal: String) -> Self {
let literal_lowercase = literal.to_lowercase();
Self {
literal,
literal_lowercase,
base,
..Default::default()
}
}
@ -54,7 +66,7 @@ impl<'a, S> LiteralCommandNode<'a, S> {
}
}
impl<S> CommandNodeTrait<S> for LiteralCommandNode<'_, S> {
impl<S> CommandNodeTrait<S> for LiteralCommandNode<S> {
fn name(&self) -> &str {
&self.literal
}

View file

@ -6,6 +6,7 @@ use super::{
use crate::{
arguments::argument_type::ArgumentType,
builder::argument_builder::ArgumentBuilder,
command::Command,
context::{command_context::CommandContext, command_context_builder::CommandContextBuilder},
exceptions::{
builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
@ -16,16 +17,24 @@ use crate::{
};
use std::{
any::Any,
collections::HashMap,
fmt::{Debug, Display, Formatter},
};
#[derive(Clone, Default, Debug)]
pub struct RootCommandNode<'a, S> {
#[derive(Default)]
pub struct RootCommandNode<S> {
// Since Rust doesn't have extending, we put the struct this is extending as the "base" field
pub base: BaseCommandNode<'a, S>,
children: HashMap<String, Box<dyn CommandNodeTrait<S>>>,
literals: HashMap<String, LiteralCommandNode<S>>,
arguments: HashMap<String, ArgumentCommandNode<S>>,
pub requirement: Box<dyn Fn(&S) -> bool>,
redirect: Option<Box<dyn CommandNodeTrait<S>>>,
modifier: Option<Box<dyn RedirectModifier<S>>>,
forks: bool,
pub command: Option<Box<dyn Command<S>>>,
}
impl<S> CommandNodeTrait<S> for RootCommandNode<'_, S> {
impl<S> CommandNodeTrait<S> for RootCommandNode<S> {
fn name(&self) -> &str {
""
}
@ -63,7 +72,7 @@ impl<S> CommandNodeTrait<S> for RootCommandNode<'_, S> {
}
}
impl<S> Display for RootCommandNode<'_, S> {
impl<S> Display for RootCommandNode<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "<root>")
}