aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-brigadier/src')
-rw-r--r--azalea-brigadier/src/arguments/bool_argument_type.rs21
-rw-r--r--azalea-brigadier/src/arguments/double_argument_type.rs54
-rw-r--r--azalea-brigadier/src/arguments/float_argument_type.rs54
-rw-r--r--[-rwxr-xr-x]azalea-brigadier/src/arguments/integer_argument_type.rs0
-rw-r--r--azalea-brigadier/src/arguments/long_argument_type.rs54
-rwxr-xr-xazalea-brigadier/src/arguments/mod.rs5
-rw-r--r--azalea-brigadier/src/arguments/string_argument_type.rs53
-rwxr-xr-xazalea-brigadier/src/builder/argument_builder.rs106
-rwxr-xr-xazalea-brigadier/src/builder/required_argument_builder.rs13
-rwxr-xr-xazalea-brigadier/src/command_dispatcher.rs127
-rwxr-xr-xazalea-brigadier/src/context/command_context.rs16
-rwxr-xr-xazalea-brigadier/src/context/command_context_builder.rs40
-rwxr-xr-xazalea-brigadier/src/context/parsed_command_node.rs6
-rwxr-xr-xazalea-brigadier/src/lib.rs15
-rwxr-xr-xazalea-brigadier/src/modifier.rs4
-rwxr-xr-xazalea-brigadier/src/parse_results.rs6
-rwxr-xr-xazalea-brigadier/src/tree/mod.rs59
17 files changed, 473 insertions, 160 deletions
diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs
new file mode 100644
index 00000000..57fa8a03
--- /dev/null
+++ b/azalea-brigadier/src/arguments/bool_argument_type.rs
@@ -0,0 +1,21 @@
+use std::{any::Any, rc::Rc};
+
+use crate::{
+ context::CommandContext, exceptions::CommandSyntaxException, string_reader::StringReader,
+};
+
+use super::ArgumentType;
+
+impl ArgumentType for bool {
+ fn parse(&self, reader: &mut StringReader) -> Result<Rc<dyn Any>, CommandSyntaxException> {
+ Ok(Rc::new(reader.read_boolean()))
+ }
+}
+
+pub fn get_bool<S>(context: &CommandContext<S>, name: &str) -> Option<bool> {
+ context
+ .argument(name)
+ .unwrap()
+ .downcast_ref::<bool>()
+ .cloned()
+}
diff --git a/azalea-brigadier/src/arguments/double_argument_type.rs b/azalea-brigadier/src/arguments/double_argument_type.rs
new file mode 100644
index 00000000..d83bfb2a
--- /dev/null
+++ b/azalea-brigadier/src/arguments/double_argument_type.rs
@@ -0,0 +1,54 @@
+use std::{any::Any, rc::Rc};
+
+use crate::{
+ context::CommandContext,
+ exceptions::{BuiltInExceptions, CommandSyntaxException},
+ string_reader::StringReader,
+};
+
+use super::ArgumentType;
+
+#[derive(Default)]
+struct Double {
+ pub minimum: Option<f64>,
+ pub maximum: Option<f64>,
+}
+
+impl ArgumentType for Double {
+ fn parse(&self, reader: &mut StringReader) -> Result<Rc<dyn Any>, CommandSyntaxException> {
+ let start = reader.cursor;
+ let result = reader.read_double()?;
+ if let Some(minimum) = self.minimum {
+ if result < minimum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::DoubleTooSmall {
+ found: result,
+ min: minimum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ if let Some(maximum) = self.maximum {
+ if result > maximum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::DoubleTooBig {
+ found: result,
+ max: maximum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ Ok(Rc::new(result))
+ }
+}
+
+pub fn double() -> impl ArgumentType {
+ Double::default()
+}
+pub fn get_double<S>(context: &CommandContext<S>, name: &str) -> Option<f64> {
+ context
+ .argument(name)
+ .unwrap()
+ .downcast_ref::<f64>()
+ .copied()
+}
diff --git a/azalea-brigadier/src/arguments/float_argument_type.rs b/azalea-brigadier/src/arguments/float_argument_type.rs
new file mode 100644
index 00000000..0d194efe
--- /dev/null
+++ b/azalea-brigadier/src/arguments/float_argument_type.rs
@@ -0,0 +1,54 @@
+use std::{any::Any, rc::Rc};
+
+use crate::{
+ context::CommandContext,
+ exceptions::{BuiltInExceptions, CommandSyntaxException},
+ string_reader::StringReader,
+};
+
+use super::ArgumentType;
+
+#[derive(Default)]
+struct Float {
+ pub minimum: Option<f32>,
+ pub maximum: Option<f32>,
+}
+
+impl ArgumentType for Float {
+ fn parse(&self, reader: &mut StringReader) -> Result<Rc<dyn Any>, CommandSyntaxException> {
+ let start = reader.cursor;
+ let result = reader.read_float()?;
+ if let Some(minimum) = self.minimum {
+ if result < minimum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::FloatTooSmall {
+ found: result,
+ min: minimum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ if let Some(maximum) = self.maximum {
+ if result > maximum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::FloatTooBig {
+ found: result,
+ max: maximum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ Ok(Rc::new(result))
+ }
+}
+
+pub fn float() -> impl ArgumentType {
+ Float::default()
+}
+pub fn get_float<S>(context: &CommandContext<S>, name: &str) -> Option<f32> {
+ context
+ .argument(name)
+ .unwrap()
+ .downcast_ref::<f32>()
+ .copied()
+}
diff --git a/azalea-brigadier/src/arguments/integer_argument_type.rs b/azalea-brigadier/src/arguments/integer_argument_type.rs
index 336046a7..336046a7 100755..100644
--- a/azalea-brigadier/src/arguments/integer_argument_type.rs
+++ b/azalea-brigadier/src/arguments/integer_argument_type.rs
diff --git a/azalea-brigadier/src/arguments/long_argument_type.rs b/azalea-brigadier/src/arguments/long_argument_type.rs
new file mode 100644
index 00000000..9b3469b6
--- /dev/null
+++ b/azalea-brigadier/src/arguments/long_argument_type.rs
@@ -0,0 +1,54 @@
+use std::{any::Any, rc::Rc};
+
+use crate::{
+ context::CommandContext,
+ exceptions::{BuiltInExceptions, CommandSyntaxException},
+ string_reader::StringReader,
+};
+
+use super::ArgumentType;
+
+#[derive(Default)]
+struct Long {
+ pub minimum: Option<i64>,
+ pub maximum: Option<i64>,
+}
+
+impl ArgumentType for Long {
+ fn parse(&self, reader: &mut StringReader) -> Result<Rc<dyn Any>, CommandSyntaxException> {
+ let start = reader.cursor;
+ let result = reader.read_long()?;
+ if let Some(minimum) = self.minimum {
+ if result < minimum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::LongTooSmall {
+ found: result,
+ min: minimum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ if let Some(maximum) = self.maximum {
+ if result > maximum {
+ reader.cursor = start;
+ return Err(BuiltInExceptions::LongTooBig {
+ found: result,
+ max: maximum,
+ }
+ .create_with_context(reader));
+ }
+ }
+ Ok(Rc::new(result))
+ }
+}
+
+pub fn long() -> impl ArgumentType {
+ Long::default()
+}
+pub fn get_long<S>(context: &CommandContext<S>, name: &str) -> Option<i64> {
+ context
+ .argument(name)
+ .unwrap()
+ .downcast_ref::<i64>()
+ .copied()
+}
diff --git a/azalea-brigadier/src/arguments/mod.rs b/azalea-brigadier/src/arguments/mod.rs
index dec39297..9d2c2cd0 100755
--- a/azalea-brigadier/src/arguments/mod.rs
+++ b/azalea-brigadier/src/arguments/mod.rs
@@ -1,4 +1,9 @@
mod argument_type;
+pub mod bool_argument_type;
+pub mod double_argument_type;
+pub mod float_argument_type;
pub mod integer_argument_type;
+pub mod long_argument_type;
+pub mod string_argument_type;
pub use argument_type::ArgumentType;
diff --git a/azalea-brigadier/src/arguments/string_argument_type.rs b/azalea-brigadier/src/arguments/string_argument_type.rs
new file mode 100644
index 00000000..27363bd4
--- /dev/null
+++ b/azalea-brigadier/src/arguments/string_argument_type.rs
@@ -0,0 +1,53 @@
+use std::{any::Any, rc::Rc};
+
+use crate::{
+ context::CommandContext, exceptions::CommandSyntaxException, string_reader::StringReader,
+};
+
+use super::ArgumentType;
+
+pub enum StringArgument {
+ /// Match up until the next space.
+ SingleWord,
+ /// Same as single word unless the argument is wrapped in quotes, in which
+ /// case it can contain spaces.
+ QuotablePhrase,
+ /// Match the rest of the input.
+ GreedyPhrase,
+}
+
+impl ArgumentType for StringArgument {
+ fn parse(&self, reader: &mut StringReader) -> Result<Rc<dyn Any>, CommandSyntaxException> {
+ let result = match self {
+ StringArgument::SingleWord => reader.read_unquoted_string().to_string(),
+ StringArgument::QuotablePhrase => reader.read_string()?,
+ StringArgument::GreedyPhrase => {
+ let text = reader.remaining().to_string();
+ reader.cursor = reader.total_length();
+ text
+ }
+ };
+ Ok(Rc::new(result))
+ }
+}
+
+/// Match up until the next space.
+pub fn word() -> impl ArgumentType {
+ StringArgument::SingleWord
+}
+/// Same as single word unless the argument is wrapped in quotes, in which case
+/// it can contain spaces.
+pub fn string() -> impl ArgumentType {
+ StringArgument::QuotablePhrase
+}
+/// Match the rest of the input.
+pub fn greedy_string() -> impl ArgumentType {
+ StringArgument::GreedyPhrase
+}
+pub fn get_string<S>(context: &CommandContext<S>, name: &str) -> Option<String> {
+ context
+ .argument(name)
+ .unwrap()
+ .downcast_ref::<String>()
+ .cloned()
+}
diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs
index 38ccc98c..643a3bd0 100755
--- a/azalea-brigadier/src/builder/argument_builder.rs
+++ b/azalea-brigadier/src/builder/argument_builder.rs
@@ -1,3 +1,5 @@
+use parking_lot::RwLock;
+
use crate::{
context::CommandContext,
modifier::RedirectModifier,
@@ -5,7 +7,7 @@ use crate::{
};
use super::{literal_argument_builder::Literal, required_argument_builder::Argument};
-use std::{cell::RefCell, fmt::Debug, rc::Rc};
+use std::{fmt::Debug, sync::Arc};
#[derive(Debug, Clone)]
pub enum ArgumentBuilderType {
@@ -18,24 +20,11 @@ pub struct ArgumentBuilder<S> {
arguments: CommandNode<S>,
command: Command<S>,
- requirement: Rc<dyn Fn(Rc<S>) -> bool>,
- target: Option<Rc<RefCell<CommandNode<S>>>>,
+ requirement: Arc<dyn Fn(Arc<S>) -> bool + Send + Sync>,
+ target: Option<Arc<RwLock<CommandNode<S>>>>,
forks: bool,
- modifier: Option<Rc<RedirectModifier<S>>>,
-}
-
-impl<S> Clone for ArgumentBuilder<S> {
- fn clone(&self) -> Self {
- Self {
- arguments: self.arguments.clone(),
- command: self.command.clone(),
- requirement: self.requirement.clone(),
- target: self.target.clone(),
- forks: self.forks,
- modifier: self.modifier.clone(),
- }
- }
+ modifier: Option<Arc<RedirectModifier<S>>>,
}
/// A node that isn't yet built.
@@ -47,54 +36,93 @@ impl<S> ArgumentBuilder<S> {
..Default::default()
},
command: None,
- requirement: Rc::new(|_| true),
+ requirement: Arc::new(|_| true),
forks: false,
modifier: None,
target: None,
}
}
- pub fn then(&mut self, argument: ArgumentBuilder<S>) -> Self {
+ /// Continue building this node with a child node.
+ ///
+ /// ```
+ /// # use azalea_brigadier::prelude::*;
+ /// # let mut subject = CommandDispatcher::<()>::new();
+ /// literal("foo").then(
+ /// literal("bar").executes(|ctx: &CommandContext<()>| 42)
+ /// )
+ /// # ;
+ /// ```
+ pub fn then(self, argument: ArgumentBuilder<S>) -> Self {
self.then_built(argument.build())
}
- pub fn then_built(&mut self, argument: CommandNode<S>) -> Self {
- self.arguments.add_child(&Rc::new(RefCell::new(argument)));
- self.clone()
+ /// Add an already built child node to this node.
+ ///
+ /// You should usually use [`Self::then`] instead.
+ pub fn then_built(mut self, argument: CommandNode<S>) -> Self {
+ self.arguments.add_child(&Arc::new(RwLock::new(argument)));
+ self
}
- pub fn executes<F>(&mut self, f: F) -> Self
+ /// Set the command to be executed when this node is reached. If this is not
+ /// present on a node, it is not a valid command.
+ ///
+ /// ```
+ /// # use azalea_brigadier::prelude::*;
+ /// # let mut subject = CommandDispatcher::<()>::new();
+ /// # subject.register(
+ /// literal("foo").executes(|ctx: &CommandContext<()>| 42)
+ /// # );
+ /// ```
+ pub fn executes<F>(mut self, f: F) -> Self
where
- F: Fn(&CommandContext<S>) -> i32 + 'static,
+ F: Fn(&CommandContext<S>) -> i32 + Send + Sync + 'static,
{
- self.command = Some(Rc::new(f));
- self.clone()
+ self.command = Some(Arc::new(f));
+ self
}
- pub fn requires<F>(&mut self, requirement: F) -> Self
+ /// Set the requirement for this node to be considered. If this is not
+ /// present on a node, it is considered to always pass.
+ ///
+ /// ```
+ /// # use azalea_brigadier::prelude::*;
+ /// # use std::sync::Arc;
+ /// # pub struct CommandSource {
+ /// # pub opped: bool,
+ /// # }
+ /// # let mut subject = CommandDispatcher::<CommandSource>::new();
+ /// # subject.register(
+ /// literal("foo")
+ /// .requires(|s: Arc<CommandSource>| s.opped)
+ /// // ...
+ /// # .executes(|ctx: &CommandContext<CommandSource>| 42)
+ /// # );
+ pub fn requires<F>(mut self, requirement: F) -> Self
where
- F: Fn(Rc<S>) -> bool + 'static,
+ F: Fn(Arc<S>) -> bool + Send + Sync + 'static,
{
- self.requirement = Rc::new(requirement);
- self.clone()
+ self.requirement = Arc::new(requirement);
+ self
}
- pub fn redirect(&mut self, target: Rc<RefCell<CommandNode<S>>>) -> Self {
+ pub fn redirect(self, target: Arc<RwLock<CommandNode<S>>>) -> Self {
self.forward(target, None, false)
}
pub fn fork(
- &mut self,
- target: Rc<RefCell<CommandNode<S>>>,
- modifier: Rc<RedirectModifier<S>>,
+ self,
+ target: Arc<RwLock<CommandNode<S>>>,
+ modifier: Arc<RedirectModifier<S>>,
) -> Self {
self.forward(target, Some(modifier), true)
}
pub fn forward(
- &mut self,
- target: Rc<RefCell<CommandNode<S>>>,
- modifier: Option<Rc<RedirectModifier<S>>>,
+ mut self,
+ target: Arc<RwLock<CommandNode<S>>>,
+ modifier: Option<Arc<RedirectModifier<S>>>,
fork: bool,
) -> Self {
if !self.arguments.children.is_empty() {
@@ -103,9 +131,11 @@ impl<S> ArgumentBuilder<S> {
self.target = Some(target);
self.modifier = modifier;
self.forks = fork;
- self.clone()
+ self
}
+ /// Manually build this node into a [`CommandNode`]. You probably don't need
+ /// to do this yourself.
pub fn build(self) -> CommandNode<S> {
let mut result = CommandNode {
value: self.arguments.value,
diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs
index 9d4d9e0a..0363d204 100755
--- a/azalea-brigadier/src/builder/required_argument_builder.rs
+++ b/azalea-brigadier/src/builder/required_argument_builder.rs
@@ -2,17 +2,17 @@ use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType};
use crate::{
arguments::ArgumentType, exceptions::CommandSyntaxException, string_reader::StringReader,
};
-use std::{any::Any, fmt::Debug, rc::Rc};
+use std::{any::Any, fmt::Debug, rc::Rc, sync::Arc};
/// An argument node type. The `T` type parameter is the type of the argument,
/// which can be anything.
#[derive(Clone)]
pub struct Argument {
pub name: String,
- parser: Rc<dyn ArgumentType>,
+ parser: Arc<dyn ArgumentType + Send + Sync>,
}
impl Argument {
- pub fn new(name: &str, parser: Rc<dyn ArgumentType>) -> Self {
+ pub fn new(name: &str, parser: Arc<dyn ArgumentType + Send + Sync>) -> Self {
Self {
name: name.to_string(),
parser,
@@ -40,6 +40,9 @@ impl Debug for Argument {
}
/// Shortcut for creating a new argument builder node.
-pub fn argument<S>(name: &str, parser: impl ArgumentType + 'static) -> ArgumentBuilder<S> {
- ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into())
+pub fn argument<S>(
+ name: &str,
+ parser: impl ArgumentType + Send + Sync + 'static,
+) -> ArgumentBuilder<S> {
+ ArgumentBuilder::new(Argument::new(name, Arc::new(parser)).into())
}
diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs
index 273b1681..595bc57d 100755
--- a/azalea-brigadier/src/command_dispatcher.rs
+++ b/azalea-brigadier/src/command_dispatcher.rs
@@ -1,3 +1,5 @@
+use parking_lot::RwLock;
+
use crate::{
builder::argument_builder::ArgumentBuilder,
context::{CommandContext, CommandContextBuilder},
@@ -6,64 +8,72 @@ use crate::{
string_reader::StringReader,
tree::CommandNode,
};
-use std::{cell::RefCell, cmp::Ordering, collections::HashMap, marker::PhantomData, mem, rc::Rc};
+use std::{cmp::Ordering, collections::HashMap, mem, rc::Rc, sync::Arc};
-#[derive(Default)]
-pub struct CommandDispatcher<S> {
- pub root: Rc<RefCell<CommandNode<S>>>,
- _marker: PhantomData<S>,
+/// The root of the command tree. You need to make this to register commands.
+///
+/// ```
+/// # use azalea_brigadier::prelude::*;
+/// # struct CommandSource;
+/// let mut subject = CommandDispatcher::<CommandSource>::new();
+/// ```
+pub struct CommandDispatcher<S>
+where
+ Self: Sync + Send,
+{
+ pub root: Arc<RwLock<CommandNode<S>>>,
}
impl<S> CommandDispatcher<S> {
pub fn new() -> Self {
Self {
- root: Rc::new(RefCell::new(CommandNode::default())),
- _marker: PhantomData,
+ root: Arc::new(RwLock::new(CommandNode::default())),
}
}
- pub fn register(&mut self, node: ArgumentBuilder<S>) -> Rc<RefCell<CommandNode<S>>> {
- let build = Rc::new(RefCell::new(node.build()));
- self.root.borrow_mut().add_child(&build);
+ /// Add a new node to the root.
+ ///
+ /// ```
+ /// # use azalea_brigadier::prelude::*;
+ /// # let mut subject = CommandDispatcher::<()>::new();
+ /// subject.register(literal("foo").executes(|_| 42));
+ /// ```
+ pub fn register(&mut self, node: ArgumentBuilder<S>) -> Arc<RwLock<CommandNode<S>>> {
+ let build = Arc::new(RwLock::new(node.build()));
+ self.root.write().add_child(&build);
build
}
- pub fn parse(&self, command: StringReader, source: Rc<S>) -> ParseResults<S> {
- let context = CommandContextBuilder::new(
- Rc::new(self.clone()),
- source,
- self.root.clone(),
- command.cursor(),
- );
+ pub fn parse(&self, command: StringReader, source: S) -> ParseResults<S> {
+ let source = Arc::new(source);
+
+ let context = CommandContextBuilder::new(self, source, self.root.clone(), command.cursor());
self.parse_nodes(&self.root, &command, context).unwrap()
}
- fn parse_nodes(
- &self,
- node: &Rc<RefCell<CommandNode<S>>>,
+ fn parse_nodes<'a>(
+ &'a self,
+ node: &Arc<RwLock<CommandNode<S>>>,
original_reader: &StringReader,
- context_so_far: CommandContextBuilder<S>,
- ) -> Result<ParseResults<S>, CommandSyntaxException> {
+ context_so_far: CommandContextBuilder<'a, S>,
+ ) -> Result<ParseResults<'a, S>, CommandSyntaxException> {
let source = context_so_far.source.clone();
let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxException>::new();
let mut potentials: Vec<ParseResults<S>> = vec![];
let cursor = original_reader.cursor();
- for child in node
- .borrow()
- .get_relevant_nodes(&mut original_reader.clone())
- {
- if !child.borrow().can_use(source.clone()) {
+ for child in node.read().get_relevant_nodes(&mut original_reader.clone()) {
+ if !child.read().can_use(source.clone()) {
continue;
}
let mut context = context_so_far.clone();
let mut reader = original_reader.clone();
let parse_with_context_result =
- child.borrow().parse_with_context(&mut reader, &mut context);
+ child.read().parse_with_context(&mut reader, &mut context);
if let Err(ex) = parse_with_context_result {
errors.insert(
- Rc::new((*child.borrow()).clone()),
+ Rc::new((*child.read()).clone()),
BuiltInExceptions::DispatcherParseException {
message: ex.message(),
}
@@ -74,7 +84,7 @@ impl<S> CommandDispatcher<S> {
}
if reader.can_read() && reader.peek() != ' ' {
errors.insert(
- Rc::new((*child.borrow()).clone()),
+ Rc::new((*child.read()).clone()),
BuiltInExceptions::DispatcherExpectedArgumentSeparator
.create_with_context(&reader),
);
@@ -82,24 +92,20 @@ impl<S> CommandDispatcher<S> {
continue;
}
- context.with_command(&child.borrow().command);
- if reader.can_read_length(if child.borrow().redirect.is_none() {
+ context.with_command(&child.read().command);
+ if reader.can_read_length(if child.read().redirect.is_none() {
2
} else {
1
}) {
reader.skip();
- if let Some(redirect) = &child.borrow().redirect {
- let child_context = CommandContextBuilder::new(
- Rc::new(self.clone()),
- source,
- redirect.clone(),
- reader.cursor,
- );
+ if let Some(redirect) = &child.read().redirect {
+ let child_context =
+ CommandContextBuilder::new(self, source, redirect.clone(), reader.cursor);
let parse = self
.parse_nodes(redirect, &reader, child_context)
.expect("Parsing nodes failed");
- context.with_child(Rc::new(parse.context));
+ context.with_child(Arc::new(parse.context));
return Ok(ParseResults {
context,
reader: parse.reader,
@@ -149,40 +155,46 @@ impl<S> CommandDispatcher<S> {
})
}
+ /// Parse and execute the command using the given input and context. The
+ /// number returned depends on the command, and may not be of significance.
+ ///
+ /// This is a shortcut for `Self::parse` and `Self::execute_parsed`.
pub fn execute(
&self,
- input: StringReader,
- source: Rc<S>,
+ input: impl Into<StringReader>,
+ source: S,
) -> Result<i32, CommandSyntaxException> {
+ let input = input.into();
+
let parse = self.parse(input, source);
Self::execute_parsed(parse)
}
pub fn add_paths(
- node: Rc<RefCell<CommandNode<S>>>,
- result: &mut Vec<Vec<Rc<RefCell<CommandNode<S>>>>>,
- parents: Vec<Rc<RefCell<CommandNode<S>>>>,
+ node: Arc<RwLock<CommandNode<S>>>,
+ result: &mut Vec<Vec<Arc<RwLock<CommandNode<S>>>>>,
+ parents: Vec<Arc<RwLock<CommandNode<S>>>>,
) {
let mut current = parents;
current.push(node.clone());
result.push(current.clone());
- for child in node.borrow().children.values() {
+ for child in node.read().children.values() {
Self::add_paths(child.clone(), result, current.clone());
}
}
pub fn get_path(&self, target: CommandNode<S>) -> Vec<String> {
- let rc_target = Rc::new(RefCell::new(target));
- let mut nodes: Vec<Vec<Rc<RefCell<CommandNode<S>>>>> = Vec::new();
+ let rc_target = Arc::new(RwLock::new(target));
+ let mut nodes: Vec<Vec<Arc<RwLock<CommandNode<S>>>>> = Vec::new();
Self::add_paths(self.root.clone(), &mut nodes, vec![]);
for list in nodes {
- if *list.last().expect("Nothing in list").borrow() == *rc_target.borrow() {
+ if *list.last().expect("Nothing in list").read() == *rc_target.read() {
let mut result: Vec<String> = Vec::with_capacity(list.len());
for node in list {
- if node != self.root {
- result.push(node.borrow().name().to_string());
+ if !Arc::ptr_eq(&node, &self.root) {
+ result.push(node.read().name().to_string());
}
}
return result;
@@ -191,10 +203,10 @@ impl<S> CommandDispatcher<S> {
vec![]
}
- pub fn find_node(&self, path: &[&str]) -> Option<Rc<RefCell<CommandNode<S>>>> {
+ pub fn find_node(&self, path: &[&str]) -> Option<Arc<RwLock<CommandNode<S>>>> {
let mut node = self.root.clone();
for name in path {
- if let Some(child) = node.clone().borrow().child(name) {
+ if let Some(child) = node.clone().read().child(name) {
node = child;
} else {
return None;
@@ -287,11 +299,8 @@ impl<S> CommandDispatcher<S> {
}
}
-impl<S> Clone for CommandDispatcher<S> {
- fn clone(&self) -> Self {
- Self {
- root: self.root.clone(),
- _marker: PhantomData,
- }
+impl<S> Default for CommandDispatcher<S> {
+ fn default() -> Self {
+ Self::new()
}
}
diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs
index 98609a6e..1734bb05 100755
--- a/azalea-brigadier/src/context/command_context.rs
+++ b/azalea-brigadier/src/context/command_context.rs
@@ -1,21 +1,23 @@
+use parking_lot::RwLock;
+
use super::{parsed_command_node::ParsedCommandNode, string_range::StringRange, ParsedArgument};
use crate::{
modifier::RedirectModifier,
tree::{Command, CommandNode},
};
-use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
+use std::{any::Any, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
/// A built `CommandContextBuilder`.
pub struct CommandContext<S> {
- pub source: Rc<S>,
+ pub source: Arc<S>,
pub input: String,
pub arguments: HashMap<String, ParsedArgument>,
pub command: Command<S>,
- pub root_node: Rc<RefCell<CommandNode<S>>>,
+ pub root_node: Arc<RwLock<CommandNode<S>>>,
pub nodes: Vec<ParsedCommandNode<S>>,
pub range: StringRange,
- pub child: Option<Rc<CommandContext<S>>>,
- pub modifier: Option<Rc<RedirectModifier<S>>>,
+ pub child: Option<Arc<CommandContext<S>>>,
+ pub modifier: Option<Arc<RedirectModifier<S>>>,
pub forks: bool,
}
@@ -54,8 +56,8 @@ impl<S> Debug for CommandContext<S> {
}
impl<S> CommandContext<S> {
- pub fn copy_for(&self, source: Rc<S>) -> Self {
- if Rc::ptr_eq(&source, &self.source) {
+ pub fn copy_for(&self, source: Arc<S>) -> Self {
+ if Arc::ptr_eq(&source, &self.source) {
return self.clone();
}
CommandContext {
diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs
index 7516ab9e..78088941 100755
--- a/azalea-brigadier/src/context/command_context_builder.rs
+++ b/azalea-brigadier/src/context/command_context_builder.rs
@@ -1,3 +1,5 @@
+use parking_lot::RwLock;
+
use super::{
command_context::CommandContext, parsed_command_node::ParsedCommandNode,
string_range::StringRange, ParsedArgument,
@@ -7,28 +9,28 @@ use crate::{
modifier::RedirectModifier,
tree::{Command, CommandNode},
};
-use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
+use std::{collections::HashMap, fmt::Debug, sync::Arc};
-pub struct CommandContextBuilder<S> {
+pub struct CommandContextBuilder<'a, S> {
pub arguments: HashMap<String, ParsedArgument>,
- pub root: Rc<RefCell<CommandNode<S>>>,
+ pub root: Arc<RwLock<CommandNode<S>>>,
pub nodes: Vec<ParsedCommandNode<S>>,
- pub dispatcher: Rc<CommandDispatcher<S>>,
- pub source: Rc<S>,
+ pub dispatcher: &'a CommandDispatcher<S>,
+ pub source: Arc<S>,
pub command: Command<S>,
- pub child: Option<Rc<CommandContextBuilder<S>>>,
+ pub child: Option<Arc<CommandContextBuilder<'a, S>>>,
pub range: StringRange,
- pub modifier: Option<Rc<RedirectModifier<S>>>,
+ pub modifier: Option<Arc<RedirectModifier<S>>>,
pub forks: bool,
}
-impl<S> Clone for CommandContextBuilder<S> {
+impl<S> Clone for CommandContextBuilder<'_, S> {
fn clone(&self) -> Self {
Self {
arguments: self.arguments.clone(),
root: self.root.clone(),
nodes: self.nodes.clone(),
- dispatcher: self.dispatcher.clone(),
+ dispatcher: self.dispatcher,
source: self.source.clone(),
command: self.command.clone(),
child: self.child.clone(),
@@ -39,11 +41,11 @@ impl<S> Clone for CommandContextBuilder<S> {
}
}
-impl<S> CommandContextBuilder<S> {
+impl<'a, S> CommandContextBuilder<'a, S> {
pub fn new(
- dispatcher: Rc<CommandDispatcher<S>>,
- source: Rc<S>,
- root_node: Rc<RefCell<CommandNode<S>>>,
+ dispatcher: &'a CommandDispatcher<S>,
+ source: Arc<S>,
+ root_node: Arc<RwLock<CommandNode<S>>>,
start: usize,
) -> Self {
Self {
@@ -64,7 +66,7 @@ impl<S> CommandContextBuilder<S> {
self.command = command.clone();
self
}
- pub fn with_child(&mut self, child: Rc<CommandContextBuilder<S>>) -> &Self {
+ pub fn with_child(&mut self, child: Arc<CommandContextBuilder<'a, S>>) -> &Self {
self.child = Some(child);
self
}
@@ -72,14 +74,14 @@ impl<S> CommandContextBuilder<S> {
self.arguments.insert(name.to_string(), argument);
self
}
- pub fn with_node(&mut self, node: Rc<RefCell<CommandNode<S>>>, range: StringRange) -> &Self {
+ pub fn with_node(&mut self, node: Arc<RwLock<CommandNode<S>>>, range: StringRange) -> &Self {
self.nodes.push(ParsedCommandNode {
node: node.clone(),
range: range.clone(),
});
self.range = StringRange::encompassing(&self.range, &range);
- self.modifier = node.borrow().modifier.clone();
- self.forks = node.borrow().forks;
+ self.modifier = node.read().modifier.clone();
+ self.forks = node.read().forks;
self
}
@@ -90,7 +92,7 @@ impl<S> CommandContextBuilder<S> {
nodes: self.nodes.clone(),
source: self.source.clone(),
command: self.command.clone(),
- child: self.child.clone().map(|c| Rc::new(c.build(input))),
+ child: self.child.clone().map(|c| Arc::new(c.build(input))),
range: self.range.clone(),
forks: self.forks,
modifier: self.modifier.clone(),
@@ -99,7 +101,7 @@ impl<S> CommandContextBuilder<S> {
}
}
-impl<S> Debug for CommandContextBuilder<S> {
+impl<S> Debug for CommandContextBuilder<'_, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CommandContextBuilder")
// .field("arguments", &self.arguments)
diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs
index ed49928d..bba5d121 100755
--- a/azalea-brigadier/src/context/parsed_command_node.rs
+++ b/azalea-brigadier/src/context/parsed_command_node.rs
@@ -1,10 +1,12 @@
+use parking_lot::RwLock;
+
use super::string_range::StringRange;
use crate::tree::CommandNode;
-use std::{cell::RefCell, rc::Rc};
+use std::sync::Arc;
#[derive(Debug)]
pub struct ParsedCommandNode<S> {
- pub node: Rc<RefCell<CommandNode<S>>>,
+ pub node: Arc<RwLock<CommandNode<S>>>,
pub range: StringRange,
}
diff --git a/azalea-brigadier/src/lib.rs b/azalea-brigadier/src/lib.rs
index eb670643..161ef83a 100755
--- a/azalea-brigadier/src/lib.rs
+++ b/azalea-brigadier/src/lib.rs
@@ -10,3 +10,18 @@ pub mod parse_results;
pub mod string_reader;
pub mod suggestion;
pub mod tree;
+
+pub mod prelude {
+ pub use crate::{
+ arguments::{
+ double_argument_type::{double, get_double},
+ float_argument_type::{float, get_float},
+ integer_argument_type::{get_integer, integer},
+ long_argument_type::{get_long, long},
+ string_argument_type::{get_string, greedy_string, string, word},
+ },
+ builder::{literal_argument_builder::literal, required_argument_builder::argument},
+ command_dispatcher::CommandDispatcher,
+ context::CommandContext,
+ };
+}
diff --git a/azalea-brigadier/src/modifier.rs b/azalea-brigadier/src/modifier.rs
index d40d59f9..bebdd0cb 100755
--- a/azalea-brigadier/src/modifier.rs
+++ b/azalea-brigadier/src/modifier.rs
@@ -1,6 +1,6 @@
-use std::rc::Rc;
+use std::sync::Arc;
use crate::{context::CommandContext, exceptions::CommandSyntaxException};
pub type RedirectModifier<S> =
- dyn Fn(&CommandContext<S>) -> Result<Vec<Rc<S>>, CommandSyntaxException>;
+ dyn Fn(&CommandContext<S>) -> Result<Vec<Arc<S>>, CommandSyntaxException> + Send + Sync;
diff --git a/azalea-brigadier/src/parse_results.rs b/azalea-brigadier/src/parse_results.rs
index 3698ae82..aa7d79ea 100755
--- a/azalea-brigadier/src/parse_results.rs
+++ b/azalea-brigadier/src/parse_results.rs
@@ -4,13 +4,13 @@ use crate::{
};
use std::{collections::HashMap, fmt::Debug, rc::Rc};
-pub struct ParseResults<S> {
- pub context: CommandContextBuilder<S>,
+pub struct ParseResults<'a, S> {
+ pub context: CommandContextBuilder<'a, S>,
pub reader: StringReader,
pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxException>,
}
-impl<S> Debug for ParseResults<S> {
+impl<S> Debug for ParseResults<'_, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParseResults")
.field("context", &self.context)
diff --git a/azalea-brigadier/src/tree/mod.rs b/azalea-brigadier/src/tree/mod.rs
index bb6af68d..cec972dc 100755
--- a/azalea-brigadier/src/tree/mod.rs
+++ b/azalea-brigadier/src/tree/mod.rs
@@ -1,3 +1,5 @@
+use parking_lot::RwLock;
+
use crate::{
builder::{
argument_builder::ArgumentBuilderType, literal_argument_builder::Literal,
@@ -8,24 +10,24 @@ use crate::{
modifier::RedirectModifier,
string_reader::StringReader,
};
-use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, ptr, rc::Rc};
+use std::{collections::HashMap, fmt::Debug, hash::Hash, ptr, sync::Arc};
-pub type Command<S> = Option<Rc<dyn Fn(&CommandContext<S>) -> i32>>;
+pub type Command<S> = Option<Arc<dyn Fn(&CommandContext<S>) -> i32 + Send + Sync>>;
/// An ArgumentBuilder that has been built.
#[non_exhaustive]
pub struct CommandNode<S> {
pub value: ArgumentBuilderType,
- pub children: HashMap<String, Rc<RefCell<CommandNode<S>>>>,
- pub literals: HashMap<String, Rc<RefCell<CommandNode<S>>>>,
- pub arguments: HashMap<String, Rc<RefCell<CommandNode<S>>>>,
+ pub children: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
+ pub literals: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
+ pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
pub command: Command<S>,
- pub requirement: Rc<dyn Fn(Rc<S>) -> bool>,
- pub redirect: Option<Rc<RefCell<CommandNode<S>>>>,
+ pub requirement: Arc<dyn Fn(Arc<S>) -> bool + Send + Sync>,
+ pub redirect: Option<Arc<RwLock<CommandNode<S>>>>,
pub forks: bool,
- pub modifier: Option<Rc<RedirectModifier<S>>>,
+ pub modifier: Option<Arc<RedirectModifier<S>>>,
}
impl<S> Clone for CommandNode<S> {
@@ -62,7 +64,7 @@ impl<S> CommandNode<S> {
}
}
- pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Rc<RefCell<CommandNode<S>>>> {
+ pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Arc<RwLock<CommandNode<S>>>> {
let literals = &self.literals;
if literals.is_empty() {
@@ -88,24 +90,24 @@ impl<S> CommandNode<S> {
}
}
- pub fn can_use(&self, source: Rc<S>) -> bool {
+ pub fn can_use(&self, source: Arc<S>) -> bool {
(self.requirement)(source)
}
- pub fn add_child(&mut self, node: &Rc<RefCell<CommandNode<S>>>) {
- let child = self.children.get(node.borrow().name());
+ pub fn add_child(&mut self, node: &Arc<RwLock<CommandNode<S>>>) {
+ let child = self.children.get(node.read().name());
if let Some(child) = child {
// We've found something to merge onto
- if let Some(command) = &node.borrow().command {
- child.borrow_mut().command = Some(command.clone());
+ if let Some(command) = &node.read().command {
+ child.write().command = Some(command.clone());
}
- for grandchild in node.borrow().children.values() {
- child.borrow_mut().add_child(grandchild);
+ for grandchild in node.read().children.values() {
+ child.write().add_child(grandchild);
}
} else {
self.children
- .insert(node.borrow().name().to_string(), node.clone());
- match &node.borrow().value {
+ .insert(node.read().name().to_string(), node.clone());
+ match &node.read().value {
ArgumentBuilderType::Literal(literal) => {
self.literals.insert(literal.value.clone(), node.clone());
}
@@ -123,7 +125,7 @@ impl<S> CommandNode<S> {
}
}
- pub fn child(&self, name: &str) -> Option<Rc<RefCell<CommandNode<S>>>> {
+ pub fn child(&self, name: &str) -> Option<Arc<RwLock<CommandNode<S>>>> {
self.children.get(name).cloned()
}
@@ -142,7 +144,7 @@ impl<S> CommandNode<S> {
};
context_builder.with_argument(&argument.name, parsed.clone());
- context_builder.with_node(Rc::new(RefCell::new(self.clone())), parsed.range);
+ context_builder.with_node(Arc::new(RwLock::new(self.clone())), parsed.range);
Ok(())
}
@@ -152,7 +154,7 @@ impl<S> CommandNode<S> {
if let Some(end) = end {
context_builder.with_node(
- Rc::new(RefCell::new(self.clone())),
+ Arc::new(RwLock::new(self.clone())),
StringRange::between(start, end),
);
return Ok(());
@@ -219,7 +221,7 @@ impl<S> Default for CommandNode<S> {
arguments: HashMap::new(),
command: None,
- requirement: Rc::new(|_| true),
+ requirement: Arc::new(|_| true),
redirect: None,
forks: false,
modifier: None,
@@ -232,7 +234,7 @@ impl<S> Hash for CommandNode<S> {
// hash the children
for (k, v) in &self.children {
k.hash(state);
- v.borrow().hash(state);
+ v.read().hash(state);
}
// i hope this works because if doesn't then that'll be a problem
ptr::hash(&self.command, state);
@@ -241,14 +243,21 @@ impl<S> Hash for CommandNode<S> {
impl<S> PartialEq for CommandNode<S> {
fn eq(&self, other: &Self) -> bool {
- if self.children != other.children {
+ if self.children.len() != other.children.len() {
return false;
}
+ for (k, v) in &self.children {
+ let other_child = other.children.get(k).unwrap();
+ if !Arc::ptr_eq(v, other_child) {
+ return false;
+ }
+ }
+
if let Some(selfexecutes) = &self.command {
// idk how to do this better since we can't compare `dyn Fn`s
if let Some(otherexecutes) = &other.command {
#[allow(clippy::vtable_address_comparisons)]
- if !Rc::ptr_eq(selfexecutes, otherexecutes) {
+ if !Arc::ptr_eq(selfexecutes, otherexecutes) {
return false;
}
} else {