1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

CommandDispatcher is now Send+Sync

This commit is contained in:
mat 2023-05-05 23:23:11 -05:00
parent 12370ab076
commit f825544e27
8 changed files with 71 additions and 68 deletions

View file

@ -7,7 +7,7 @@ use crate::{
};
use super::{literal_argument_builder::Literal, required_argument_builder::Argument};
use std::{fmt::Debug, rc::Rc, sync::Arc};
use std::{fmt::Debug, sync::Arc};
#[derive(Debug, Clone)]
pub enum ArgumentBuilderType {
@ -20,11 +20,11 @@ pub struct ArgumentBuilder<S> {
arguments: CommandNode<S>,
command: Command<S>,
requirement: Rc<dyn Fn(Rc<S>) -> bool>,
requirement: Arc<dyn Fn(Arc<S>) -> bool + Send + Sync>,
target: Option<Arc<RwLock<CommandNode<S>>>>,
forks: bool,
modifier: Option<Rc<RedirectModifier<S>>>,
modifier: Option<Arc<RedirectModifier<S>>>,
}
/// A node that isn't yet built.
@ -36,7 +36,7 @@ impl<S> ArgumentBuilder<S> {
..Default::default()
},
command: None,
requirement: Rc::new(|_| true),
requirement: Arc::new(|_| true),
forks: false,
modifier: None,
target: None,
@ -54,17 +54,17 @@ impl<S> ArgumentBuilder<S> {
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.command = Some(Arc::new(f));
self
}
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.requirement = Arc::new(requirement);
self
}
@ -75,7 +75,7 @@ impl<S> ArgumentBuilder<S> {
pub fn fork(
self,
target: Arc<RwLock<CommandNode<S>>>,
modifier: Rc<RedirectModifier<S>>,
modifier: Arc<RedirectModifier<S>>,
) -> Self {
self.forward(target, Some(modifier), true)
}
@ -83,7 +83,7 @@ impl<S> ArgumentBuilder<S> {
pub fn forward(
mut self,
target: Arc<RwLock<CommandNode<S>>>,
modifier: Option<Rc<RedirectModifier<S>>>,
modifier: Option<Arc<RedirectModifier<S>>>,
fork: bool,
) -> Self {
if !self.arguments.children.is_empty() {

View file

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

View file

@ -13,8 +13,8 @@ use std::{cmp::Ordering, collections::HashMap, mem, rc::Rc, sync::Arc};
/// The root of the command tree. You need to make this to register commands.
#[derive(Default)]
pub struct CommandDispatcher<S>
// where
// Self: Sync + Send,
where
Self: Sync + Send,
{
pub root: Arc<RwLock<CommandNode<S>>>,
}
@ -32,7 +32,7 @@ impl<S> CommandDispatcher<S> {
build
}
pub fn parse(&self, command: StringReader, source: Rc<S>) -> ParseResults<S> {
pub fn parse(&self, command: StringReader, source: Arc<S>) -> ParseResults<S> {
let context = CommandContextBuilder::new(self, source, self.root.clone(), command.cursor());
self.parse_nodes(&self.root, &command, context).unwrap()
}
@ -91,7 +91,7 @@ impl<S> CommandDispatcher<S> {
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,
@ -144,7 +144,7 @@ impl<S> CommandDispatcher<S> {
pub fn execute(
&self,
input: StringReader,
source: Rc<S>,
source: Arc<S>,
) -> Result<i32, CommandSyntaxException> {
let parse = self.parse(input, source);
Self::execute_parsed(parse)

View file

@ -9,15 +9,15 @@ 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: 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,
}
@ -56,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 {

View file

@ -9,18 +9,18 @@ use crate::{
modifier::RedirectModifier,
tree::{Command, CommandNode},
};
use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
use std::{collections::HashMap, fmt::Debug, sync::Arc};
pub struct CommandContextBuilder<'a, S> {
pub arguments: HashMap<String, ParsedArgument>,
pub root: Arc<RwLock<CommandNode<S>>>,
pub nodes: Vec<ParsedCommandNode<S>>,
pub dispatcher: &'a CommandDispatcher<S>,
pub source: Rc<S>,
pub source: Arc<S>,
pub command: Command<S>,
pub child: Option<Rc<CommandContextBuilder<'a, 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,
}
@ -44,7 +44,7 @@ impl<S> Clone for CommandContextBuilder<'_, S> {
impl<'a, S> CommandContextBuilder<'a, S> {
pub fn new(
dispatcher: &'a CommandDispatcher<S>,
source: Rc<S>,
source: Arc<S>,
root_node: Arc<RwLock<CommandNode<S>>>,
start: usize,
) -> Self {
@ -66,7 +66,7 @@ impl<'a, S> CommandContextBuilder<'a, S> {
self.command = command.clone();
self
}
pub fn with_child(&mut self, child: Rc<CommandContextBuilder<'a, S>>) -> &Self {
pub fn with_child(&mut self, child: Arc<CommandContextBuilder<'a, S>>) -> &Self {
self.child = Some(child);
self
}
@ -92,7 +92,7 @@ impl<'a, S> CommandContextBuilder<'a, 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(),

View file

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

View file

@ -10,9 +10,9 @@ use crate::{
modifier::RedirectModifier,
string_reader::StringReader,
};
use std::{collections::HashMap, fmt::Debug, hash::Hash, ptr, rc::Rc, sync::Arc};
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]
@ -24,10 +24,10 @@ pub struct CommandNode<S> {
pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
pub command: Command<S>,
pub requirement: Rc<dyn Fn(Rc<S>) -> bool>,
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> {
@ -90,7 +90,7 @@ 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)
}
@ -221,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,
@ -257,7 +257,7 @@ impl<S> PartialEq for CommandNode<S> {
// 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 {

View file

@ -1,4 +1,4 @@
use std::rc::Rc;
use std::sync::Arc;
use azalea_brigadier::{
arguments::integer_argument_type::integer,
@ -25,7 +25,7 @@ fn create_and_execute_command() {
assert_eq!(
subject
.execute("foo".into(), Rc::new(CommandSource {}))
.execute("foo".into(), Arc::new(CommandSource {}))
.unwrap(),
42
);
@ -38,7 +38,7 @@ fn create_and_execute_offset_command() {
assert_eq!(
subject
.execute(input_with_offset("/foo", 1), Rc::new(CommandSource {}))
.execute(input_with_offset("/foo", 1), Arc::new(CommandSource {}))
.unwrap(),
42
);
@ -52,13 +52,13 @@ fn create_and_merge_commands() {
assert_eq!(
subject
.execute("base foo".into(), Rc::new(CommandSource {}))
.execute("base foo".into(), Arc::new(CommandSource {}))
.unwrap(),
42
);
assert_eq!(
subject
.execute("base bar".into(), Rc::new(CommandSource {}))
.execute("base bar".into(), Arc::new(CommandSource {}))
.unwrap(),
42
);
@ -70,7 +70,7 @@ fn execute_unknown_command() {
subject.register(literal("bar"));
subject.register(literal("baz"));
let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("foo".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -85,7 +85,7 @@ fn execute_impermissible_command() {
let mut subject = CommandDispatcher::new();
subject.register(literal("foo").requires(|_| false));
let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("foo".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -100,7 +100,7 @@ fn execute_empty_command() {
let mut subject = CommandDispatcher::new();
subject.register(literal(""));
let execute_result = subject.execute("".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -115,7 +115,7 @@ fn execute_unknown_subcommand() {
let mut subject = CommandDispatcher::new();
subject.register(literal("foo").executes(|_| 42));
let execute_result = subject.execute("foo bar".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("foo bar".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -130,7 +130,7 @@ fn execute_incorrect_literal() {
let mut subject = CommandDispatcher::new();
subject.register(literal("foo").executes(|_| 42).then(literal("bar")));
let execute_result = subject.execute("foo baz".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("foo baz".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -150,7 +150,7 @@ fn execute_ambiguous_incorrect_argument() {
.then(literal("baz")),
);
let execute_result = subject.execute("foo unknown".into(), Rc::new(CommandSource {}));
let execute_result = subject.execute("foo unknown".into(), Arc::new(CommandSource {}));
let err = execute_result.err().unwrap();
match err.type_ {
@ -174,7 +174,7 @@ fn execute_subcommand() {
assert_eq!(
subject
.execute("foo =".into(), Rc::new(CommandSource {}))
.execute("foo =".into(), Arc::new(CommandSource {}))
.unwrap(),
100
);
@ -185,7 +185,7 @@ fn parse_incomplete_literal() {
let mut subject = CommandDispatcher::new();
subject.register(literal("foo").then(literal("bar").executes(|_| 42)));
let parse = subject.parse("foo ".into(), Rc::new(CommandSource {}));
let parse = subject.parse("foo ".into(), Arc::new(CommandSource {}));
assert_eq!(parse.reader.remaining(), " ");
assert_eq!(parse.context.nodes.len(), 1);
}
@ -195,7 +195,7 @@ fn parse_incomplete_argument() {
let mut subject = CommandDispatcher::new();
subject.register(literal("foo").then(argument("bar", integer()).executes(|_| 42)));
let parse = subject.parse("foo ".into(), Rc::new(CommandSource {}));
let parse = subject.parse("foo ".into(), Arc::new(CommandSource {}));
assert_eq!(parse.reader.remaining(), " ");
assert_eq!(parse.context.nodes.len(), 1);
}
@ -212,7 +212,7 @@ fn execute_ambiguious_parent_subcommand() {
assert_eq!(
subject
.execute("test 1 2".into(), Rc::new(CommandSource {}))
.execute("test 1 2".into(), Arc::new(CommandSource {}))
.unwrap(),
100
);
@ -232,7 +232,7 @@ fn execute_ambiguious_parent_subcommand_via_redirect() {
assert_eq!(
subject
.execute("redirect 1 2".into(), Rc::new(CommandSource {}))
.execute("redirect 1 2".into(), Arc::new(CommandSource {}))
.unwrap(),
100
);
@ -248,7 +248,7 @@ fn execute_redirected_multiple_times() {
let input = "redirected redirected actual";
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
let parse = subject.parse(input.into(), Arc::new(CommandSource {}));
assert_eq!(parse.context.range.get(input), "redirected");
assert_eq!(parse.context.nodes.len(), 1);
assert_eq!(*parse.context.root.read(), *root.read());
@ -287,19 +287,19 @@ fn execute_redirected_multiple_times() {
fn execute_redirected() {
let mut subject = CommandDispatcher::new();
let source1 = Rc::new(CommandSource {});
let source2 = Rc::new(CommandSource {});
let source1 = Arc::new(CommandSource {});
let source2 = Arc::new(CommandSource {});
let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Rc<CommandSource>>, CommandSyntaxException> {
let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Arc<CommandSource>>, CommandSyntaxException> {
Ok(vec![source1.clone(), source2.clone()])
};
let concrete_node = subject.register(literal("actual").executes(|_| 42));
let redirect_node =
subject.register(literal("redirected").fork(subject.root.clone(), Rc::new(modifier)));
subject.register(literal("redirected").fork(subject.root.clone(), Arc::new(modifier)));
let input = "redirected actual";
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
let parse = subject.parse(input.into(), Arc::new(CommandSource {}));
assert_eq!(parse.context.range.get(input), "redirected");
assert_eq!(parse.context.nodes.len(), 1);
assert_eq!(*parse.context.root.read(), *subject.root.read());
@ -314,7 +314,7 @@ fn execute_redirected() {
assert_eq!(*parse.context.root.read(), *subject.root.read());
assert_eq!(parent.nodes[0].range, parent.range);
assert_eq!(*parent.nodes[0].node.read(), *concrete_node.read());
assert_eq!(parent.source, Rc::new(CommandSource {}));
assert_eq!(parent.source, Arc::new(CommandSource {}));
assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2);
}
@ -329,7 +329,7 @@ fn execute_orphaned_subcommand() {
.executes(|_| 42),
);
let result = subject.execute("foo 5".into(), Rc::new(CommandSource {}));
let result = subject.execute("foo 5".into(), Arc::new(CommandSource {}));
assert!(result.is_err());
let result = result.unwrap_err();
assert_eq!(
@ -348,7 +348,7 @@ fn execute_invalid_other() {
assert_eq!(
subject
.execute("world".into(), Rc::new(CommandSource {}))
.execute("world".into(), Arc::new(CommandSource {}))
.unwrap(),
42
);
@ -364,7 +364,7 @@ fn parse_no_space_separator() {
.executes(|_| 42),
);
let result = subject.execute("foo$".into(), Rc::new(CommandSource {}));
let result = subject.execute("foo$".into(), Arc::new(CommandSource {}));
assert!(result.is_err());
let result = result.unwrap_err();
assert_eq!(
@ -384,7 +384,7 @@ fn execute_invalid_subcommand() {
.executes(|_| 42),
);
let result = subject.execute("foo bar".into(), Rc::new(CommandSource {}));
let result = subject.execute("foo bar".into(), Arc::new(CommandSource {}));
assert!(result.is_err());
let result = result.unwrap_err();
// this fails for some reason, i blame mojang