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 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)] #[derive(Debug, Clone)]
pub enum ArgumentBuilderType { pub enum ArgumentBuilderType {
@ -20,11 +20,11 @@ pub struct ArgumentBuilder<S> {
arguments: CommandNode<S>, arguments: CommandNode<S>,
command: Command<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>>>>, target: Option<Arc<RwLock<CommandNode<S>>>>,
forks: bool, forks: bool,
modifier: Option<Rc<RedirectModifier<S>>>, modifier: Option<Arc<RedirectModifier<S>>>,
} }
/// A node that isn't yet built. /// A node that isn't yet built.
@ -36,7 +36,7 @@ impl<S> ArgumentBuilder<S> {
..Default::default() ..Default::default()
}, },
command: None, command: None,
requirement: Rc::new(|_| true), requirement: Arc::new(|_| true),
forks: false, forks: false,
modifier: None, modifier: None,
target: None, target: None,
@ -54,17 +54,17 @@ impl<S> ArgumentBuilder<S> {
pub fn executes<F>(mut self, f: F) -> Self pub fn executes<F>(mut self, f: F) -> Self
where 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 self
} }
pub fn requires<F>(mut self, requirement: F) -> Self pub fn requires<F>(mut self, requirement: F) -> Self
where 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 self
} }
@ -75,7 +75,7 @@ impl<S> ArgumentBuilder<S> {
pub fn fork( pub fn fork(
self, self,
target: Arc<RwLock<CommandNode<S>>>, target: Arc<RwLock<CommandNode<S>>>,
modifier: Rc<RedirectModifier<S>>, modifier: Arc<RedirectModifier<S>>,
) -> Self { ) -> Self {
self.forward(target, Some(modifier), true) self.forward(target, Some(modifier), true)
} }
@ -83,7 +83,7 @@ impl<S> ArgumentBuilder<S> {
pub fn forward( pub fn forward(
mut self, mut self,
target: Arc<RwLock<CommandNode<S>>>, target: Arc<RwLock<CommandNode<S>>>,
modifier: Option<Rc<RedirectModifier<S>>>, modifier: Option<Arc<RedirectModifier<S>>>,
fork: bool, fork: bool,
) -> Self { ) -> Self {
if !self.arguments.children.is_empty() { if !self.arguments.children.is_empty() {

View file

@ -2,17 +2,17 @@ use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType};
use crate::{ use crate::{
arguments::ArgumentType, exceptions::CommandSyntaxException, string_reader::StringReader, 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, /// An argument node type. The `T` type parameter is the type of the argument,
/// which can be anything. /// which can be anything.
#[derive(Clone)] #[derive(Clone)]
pub struct Argument { pub struct Argument {
pub name: String, pub name: String,
parser: Rc<dyn ArgumentType>, parser: Arc<dyn ArgumentType + Send + Sync>,
} }
impl Argument { 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 { Self {
name: name.to_string(), name: name.to_string(),
parser, parser,
@ -40,6 +40,9 @@ impl Debug for Argument {
} }
/// Shortcut for creating a new argument builder node. /// Shortcut for creating a new argument builder node.
pub fn argument<S>(name: &str, parser: impl ArgumentType + 'static) -> ArgumentBuilder<S> { pub fn argument<S>(
ArgumentBuilder::new(Argument::new(name, Rc::new(parser)).into()) 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. /// The root of the command tree. You need to make this to register commands.
#[derive(Default)] #[derive(Default)]
pub struct CommandDispatcher<S> pub struct CommandDispatcher<S>
// where where
// Self: Sync + Send, Self: Sync + Send,
{ {
pub root: Arc<RwLock<CommandNode<S>>>, pub root: Arc<RwLock<CommandNode<S>>>,
} }
@ -32,7 +32,7 @@ impl<S> CommandDispatcher<S> {
build 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()); let context = CommandContextBuilder::new(self, source, self.root.clone(), command.cursor());
self.parse_nodes(&self.root, &command, context).unwrap() self.parse_nodes(&self.root, &command, context).unwrap()
} }
@ -91,7 +91,7 @@ impl<S> CommandDispatcher<S> {
let parse = self let parse = self
.parse_nodes(redirect, &reader, child_context) .parse_nodes(redirect, &reader, child_context)
.expect("Parsing nodes failed"); .expect("Parsing nodes failed");
context.with_child(Rc::new(parse.context)); context.with_child(Arc::new(parse.context));
return Ok(ParseResults { return Ok(ParseResults {
context, context,
reader: parse.reader, reader: parse.reader,
@ -144,7 +144,7 @@ impl<S> CommandDispatcher<S> {
pub fn execute( pub fn execute(
&self, &self,
input: StringReader, input: StringReader,
source: Rc<S>, source: Arc<S>,
) -> Result<i32, CommandSyntaxException> { ) -> Result<i32, CommandSyntaxException> {
let parse = self.parse(input, source); let parse = self.parse(input, source);
Self::execute_parsed(parse) 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`. /// A built `CommandContextBuilder`.
pub struct CommandContext<S> { pub struct CommandContext<S> {
pub source: Rc<S>, pub source: Arc<S>,
pub input: String, pub input: String,
pub arguments: HashMap<String, ParsedArgument>, pub arguments: HashMap<String, ParsedArgument>,
pub command: Command<S>, pub command: Command<S>,
pub root_node: Arc<RwLock<CommandNode<S>>>, pub root_node: Arc<RwLock<CommandNode<S>>>,
pub nodes: Vec<ParsedCommandNode<S>>, pub nodes: Vec<ParsedCommandNode<S>>,
pub range: StringRange, pub range: StringRange,
pub child: Option<Rc<CommandContext<S>>>, pub child: Option<Arc<CommandContext<S>>>,
pub modifier: Option<Rc<RedirectModifier<S>>>, pub modifier: Option<Arc<RedirectModifier<S>>>,
pub forks: bool, pub forks: bool,
} }
@ -56,8 +56,8 @@ impl<S> Debug for CommandContext<S> {
} }
impl<S> CommandContext<S> { impl<S> CommandContext<S> {
pub fn copy_for(&self, source: Rc<S>) -> Self { pub fn copy_for(&self, source: Arc<S>) -> Self {
if Rc::ptr_eq(&source, &self.source) { if Arc::ptr_eq(&source, &self.source) {
return self.clone(); return self.clone();
} }
CommandContext { CommandContext {

View file

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

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::sync::Arc;
use crate::{context::CommandContext, exceptions::CommandSyntaxException}; use crate::{context::CommandContext, exceptions::CommandSyntaxException};
pub type RedirectModifier<S> = 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, modifier::RedirectModifier,
string_reader::StringReader, 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. /// An ArgumentBuilder that has been built.
#[non_exhaustive] #[non_exhaustive]
@ -24,10 +24,10 @@ pub struct CommandNode<S> {
pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>, pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
pub command: Command<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 redirect: Option<Arc<RwLock<CommandNode<S>>>>,
pub forks: bool, pub forks: bool,
pub modifier: Option<Rc<RedirectModifier<S>>>, pub modifier: Option<Arc<RedirectModifier<S>>>,
} }
impl<S> Clone for CommandNode<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) (self.requirement)(source)
} }
@ -221,7 +221,7 @@ impl<S> Default for CommandNode<S> {
arguments: HashMap::new(), arguments: HashMap::new(),
command: None, command: None,
requirement: Rc::new(|_| true), requirement: Arc::new(|_| true),
redirect: None, redirect: None,
forks: false, forks: false,
modifier: None, 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 // idk how to do this better since we can't compare `dyn Fn`s
if let Some(otherexecutes) = &other.command { if let Some(otherexecutes) = &other.command {
#[allow(clippy::vtable_address_comparisons)] #[allow(clippy::vtable_address_comparisons)]
if !Rc::ptr_eq(selfexecutes, otherexecutes) { if !Arc::ptr_eq(selfexecutes, otherexecutes) {
return false; return false;
} }
} else { } else {

View file

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