diff --git a/Cargo.lock b/Cargo.lock index cb1098cc..dcf982f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,6 +233,7 @@ version = "0.6.0" dependencies = [ "azalea-buf", "azalea-chat", + "parking_lot", ] [[package]] diff --git a/azalea-brigadier/Cargo.toml b/azalea-brigadier/Cargo.toml index 254ccc83..a1f5966b 100644 --- a/azalea-brigadier/Cargo.toml +++ b/azalea-brigadier/Cargo.toml @@ -11,6 +11,7 @@ version = "0.6.0" [dependencies] azalea-buf = {path = "../azalea-buf", version = "^0.6.0", optional = true} azalea-chat = {path = "../azalea-chat", version = "^0.6.0", optional = true} +parking_lot = "0.12.1" [features] azalea-buf = ["dep:azalea-buf", "dep:azalea-chat"] diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index cfaff618..a1f3d6ae 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, rc::Rc, sync::Arc}; #[derive(Debug, Clone)] pub enum ArgumentBuilderType { @@ -19,7 +21,7 @@ pub struct ArgumentBuilder { command: Command, requirement: Rc) -> bool>, - target: Option>>>, + target: Option>>>, forks: bool, modifier: Option>>, @@ -46,7 +48,7 @@ impl ArgumentBuilder { } pub fn then_built(mut self, argument: CommandNode) -> Self { - self.arguments.add_child(&Rc::new(RefCell::new(argument))); + self.arguments.add_child(&Arc::new(RwLock::new(argument))); self } @@ -66,13 +68,13 @@ impl ArgumentBuilder { self } - pub fn redirect(self, target: Rc>>) -> Self { + pub fn redirect(self, target: Arc>>) -> Self { self.forward(target, None, false) } pub fn fork( self, - target: Rc>>, + target: Arc>>, modifier: Rc>, ) -> Self { self.forward(target, Some(modifier), true) @@ -80,7 +82,7 @@ impl ArgumentBuilder { pub fn forward( mut self, - target: Rc>>, + target: Arc>>, modifier: Option>>, fork: bool, ) -> Self { diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs index 29fadfd1..0d84171e 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,26 +8,27 @@ 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}; /// The root of the command tree. You need to make this to register commands. #[derive(Default)] -pub struct CommandDispatcher<'a, S> { - pub root: Rc>>, - _marker: PhantomData<(S, &'a ())>, +pub struct CommandDispatcher +// where +// Self: Sync + Send, +{ + pub root: Arc>>, } -impl<'a, S> CommandDispatcher<'a, S> { +impl CommandDispatcher { 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) -> Rc>> { - let build = Rc::new(RefCell::new(node.build())); - self.root.borrow_mut().add_child(&build); + pub fn register(&mut self, node: ArgumentBuilder) -> Arc>> { + let build = Arc::new(RwLock::new(node.build())); + self.root.write().add_child(&build); build } @@ -34,9 +37,9 @@ impl<'a, S> CommandDispatcher<'a, S> { self.parse_nodes(&self.root, &command, context).unwrap() } - fn parse_nodes( + fn parse_nodes<'a>( &'a self, - node: &Rc>>, + node: &Arc>>, original_reader: &StringReader, context_so_far: CommandContextBuilder<'a, S>, ) -> Result, CommandSyntaxException> { @@ -45,21 +48,18 @@ impl<'a, S> CommandDispatcher<'a, S> { let mut potentials: Vec> = 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(), } @@ -70,7 +70,7 @@ impl<'a, S> CommandDispatcher<'a, 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), ); @@ -78,14 +78,14 @@ impl<'a, S> CommandDispatcher<'a, 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 { + if let Some(redirect) = &child.read().redirect { let child_context = CommandContextBuilder::new(self, source, redirect.clone(), reader.cursor); let parse = self @@ -151,30 +151,30 @@ impl<'a, S> CommandDispatcher<'a, S> { } pub fn add_paths( - node: Rc>>, - result: &mut Vec>>>>, - parents: Vec>>>, + node: Arc>>, + result: &mut Vec>>>>, + parents: Vec>>>, ) { 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) -> Vec { - let rc_target = Rc::new(RefCell::new(target)); - let mut nodes: Vec>>>> = Vec::new(); + let rc_target = Arc::new(RwLock::new(target)); + let mut nodes: Vec>>>> = 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 = 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; @@ -183,10 +183,10 @@ impl<'a, S> CommandDispatcher<'a, S> { vec![] } - pub fn find_node(&self, path: &[&str]) -> Option>>> { + pub fn find_node(&self, path: &[&str]) -> Option>>> { 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; diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index 98609a6e..88af2002 100755 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -1,9 +1,11 @@ +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 { @@ -11,7 +13,7 @@ pub struct CommandContext { pub input: String, pub arguments: HashMap, pub command: Command, - pub root_node: Rc>>, + pub root_node: Arc>>, pub nodes: Vec>, pub range: StringRange, pub child: Option>>, diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index b0677158..54063879 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,13 +9,13 @@ use crate::{ modifier::RedirectModifier, tree::{Command, CommandNode}, }; -use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; +use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc}; pub struct CommandContextBuilder<'a, S> { pub arguments: HashMap, - pub root: Rc>>, + pub root: Arc>>, pub nodes: Vec>, - pub dispatcher: &'a CommandDispatcher<'a, S>, + pub dispatcher: &'a CommandDispatcher, pub source: Rc, pub command: Command, pub child: Option>>, @@ -28,7 +30,7 @@ impl Clone for CommandContextBuilder<'_, S> { 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(), @@ -43,7 +45,7 @@ impl<'a, S> CommandContextBuilder<'a, S> { pub fn new( dispatcher: &'a CommandDispatcher, source: Rc, - root_node: Rc>>, + root_node: Arc>>, start: usize, ) -> Self { Self { @@ -72,14 +74,14 @@ impl<'a, S> CommandContextBuilder<'a, S> { self.arguments.insert(name.to_string(), argument); self } - pub fn with_node(&mut self, node: Rc>>, range: StringRange) -> &Self { + pub fn with_node(&mut self, node: Arc>>, 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 } 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 { - pub node: Rc>>, + pub node: Arc>>, pub range: StringRange, } diff --git a/azalea-brigadier/src/tree/mod.rs b/azalea-brigadier/src/tree/mod.rs index bb6af68d..902e288b 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,7 +10,7 @@ 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, rc::Rc, sync::Arc}; pub type Command = Option) -> i32>>; @@ -17,13 +19,13 @@ pub type Command = Option) -> i32>>; pub struct CommandNode { pub value: ArgumentBuilderType, - pub children: HashMap>>>, - pub literals: HashMap>>>, - pub arguments: HashMap>>>, + pub children: HashMap>>>, + pub literals: HashMap>>>, + pub arguments: HashMap>>>, pub command: Command, pub requirement: Rc) -> bool>, - pub redirect: Option>>>, + pub redirect: Option>>>, pub forks: bool, pub modifier: Option>>, } @@ -62,7 +64,7 @@ impl CommandNode { } } - pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec>>> { + pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec>>> { let literals = &self.literals; if literals.is_empty() { @@ -92,20 +94,20 @@ impl CommandNode { (self.requirement)(source) } - pub fn add_child(&mut self, node: &Rc>>) { - let child = self.children.get(node.borrow().name()); + pub fn add_child(&mut self, node: &Arc>>) { + 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 CommandNode { } } - pub fn child(&self, name: &str) -> Option>>> { + pub fn child(&self, name: &str) -> Option>>> { self.children.get(name).cloned() } @@ -142,7 +144,7 @@ impl CommandNode { }; 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 CommandNode { 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(()); @@ -232,7 +234,7 @@ impl Hash for CommandNode { // 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,9 +243,16 @@ impl Hash for CommandNode { impl PartialEq for CommandNode { 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 { diff --git a/azalea-brigadier/tests/builder/argument_builder_test.rs b/azalea-brigadier/tests/builder/argument_builder_test.rs index e570c988..ee44f5e6 100755 --- a/azalea-brigadier/tests/builder/argument_builder_test.rs +++ b/azalea-brigadier/tests/builder/argument_builder_test.rs @@ -17,13 +17,14 @@ use super::ArgumentBuilder; // @Test // public void testArguments() throws Exception { -// final RequiredArgumentBuilder argument = argument("bar", integer()); +// final RequiredArgumentBuilder argument = argument("bar", +// integer()); // builder.then(argument); // assertThat(builder.getArguments(), hasSize(1)); -// assertThat(builder.getArguments(), hasItem((CommandNode) argument.build())); -// } +// assertThat(builder.getArguments(), hasItem((CommandNode) +// argument.build())); } #[test] fn test_arguments() { @@ -37,7 +38,7 @@ fn test_arguments() { .arguments .children .values() - .any(|e| *e.borrow() == *built_argument)); + .any(|e| *e.read() == *built_argument)); } // @Test @@ -61,8 +62,8 @@ fn test_arguments() { // builder.then(literal("foo")); // } -// private static class TestableArgumentBuilder extends ArgumentBuilder> { -// @Override +// private static class TestableArgumentBuilder extends +// ArgumentBuilder> { @Override // protected TestableArgumentBuilder getThis() { // return this; // } diff --git a/azalea-brigadier/tests/command_dispatcher_test.rs b/azalea-brigadier/tests/command_dispatcher_test.rs index e30dd2c1..fb0085ba 100755 --- a/azalea-brigadier/tests/command_dispatcher_test.rs +++ b/azalea-brigadier/tests/command_dispatcher_test.rs @@ -251,31 +251,34 @@ fn execute_redirected_multiple_times() { let parse = subject.parse(input.into(), Rc::new(CommandSource {})); assert_eq!(parse.context.range.get(input), "redirected"); assert_eq!(parse.context.nodes.len(), 1); - assert_eq!(parse.context.root, root); + assert_eq!(*parse.context.root.read(), *root.read()); assert_eq!(parse.context.nodes[0].range, parse.context.range); - assert_eq!(parse.context.nodes[0].node, redirect_node); + assert_eq!(*parse.context.nodes[0].node.read(), *redirect_node.read()); let child1 = parse.context.child.clone(); assert!(child1.is_some()); assert_eq!(child1.clone().unwrap().range.get(input), "redirected"); assert_eq!(child1.clone().unwrap().nodes.len(), 1); - assert_eq!(child1.clone().unwrap().root, root); + assert_eq!(*child1.clone().unwrap().root.read(), *root.read()); assert_eq!( child1.clone().unwrap().nodes[0].range, child1.clone().unwrap().range ); - assert_eq!(child1.clone().unwrap().nodes[0].node, redirect_node); + assert_eq!( + *child1.clone().unwrap().nodes[0].node.read(), + *redirect_node.read() + ); let child2 = child1.unwrap().child.clone(); assert!(child2.is_some()); assert_eq!(child2.clone().unwrap().range.get(input), "actual"); assert_eq!(child2.clone().unwrap().nodes.len(), 1); - assert_eq!(child2.clone().unwrap().root, root); + assert_eq!(*child2.clone().unwrap().root.read(), *root.read()); assert_eq!( child2.clone().unwrap().nodes[0].range, child2.clone().unwrap().range ); - assert_eq!(child2.unwrap().nodes[0].node, concrete_node); + assert_eq!(*child2.unwrap().nodes[0].node.read(), *concrete_node.read()); assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 42); } @@ -299,18 +302,18 @@ fn execute_redirected() { let parse = subject.parse(input.into(), Rc::new(CommandSource {})); assert_eq!(parse.context.range.get(input), "redirected"); assert_eq!(parse.context.nodes.len(), 1); - assert_eq!(parse.context.root, subject.root); + assert_eq!(*parse.context.root.read(), *subject.root.read()); assert_eq!(parse.context.nodes[0].range, parse.context.range); - assert_eq!(parse.context.nodes[0].node, redirect_node); + assert_eq!(*parse.context.nodes[0].node.read(), *redirect_node.read()); let parent = parse.context.child.clone(); assert!(parent.is_some()); let parent = parent.unwrap(); assert_eq!(parent.range.get(input), "actual"); assert_eq!(parent.nodes.len(), 1); - assert_eq!(parse.context.root, subject.root); + assert_eq!(*parse.context.root.read(), *subject.root.read()); assert_eq!(parent.nodes[0].range, parent.range); - assert_eq!(parent.nodes[0].node, concrete_node); + assert_eq!(*parent.nodes[0].node.read(), *concrete_node.read()); assert_eq!(parent.source, Rc::new(CommandSource {})); assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2); @@ -406,5 +409,5 @@ fn get_path() { fn find_node_doesnt_exist() { let subject = CommandDispatcher::<()>::new(); - assert_eq!(subject.find_node(&["foo", "bar"]), None) + assert!(subject.find_node(&["foo", "bar"]).is_none()) }