diff options
| author | mat <git@matdoes.dev> | 2025-05-30 20:07:28 -0330 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-05-30 16:37:40 -0700 |
| commit | a5e7ff771d657258cedcc7a8b3ce265c655f0860 (patch) | |
| tree | ea5fdbbee32c1b9917a7ece03f6a1a70ee8e63fa | |
| parent | da73b4316de4b26322c53f14222c7751a0be55a1 (diff) | |
| download | azalea-drasl-a5e7ff771d657258cedcc7a8b3ce265c655f0860.tar.xz | |
implement missing brigadier features and cleanup some more
26 files changed, 436 insertions, 289 deletions
diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs index d7bfa7d6..45859538 100644 --- a/azalea-brigadier/src/arguments/argument_type.rs +++ b/azalea-brigadier/src/arguments/argument_type.rs @@ -1,13 +1,13 @@ use std::{any::Any, sync::Arc}; use crate::{ - exceptions::CommandSyntaxException, + errors::CommandSyntaxError, string_reader::StringReader, suggestion::{Suggestions, SuggestionsBuilder}, }; pub trait ArgumentType { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException>; + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError>; fn list_suggestions(&self, _builder: SuggestionsBuilder) -> Suggestions { Suggestions::default() diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs index efb86509..225e985e 100644 --- a/azalea-brigadier/src/arguments/bool_argument_type.rs +++ b/azalea-brigadier/src/arguments/bool_argument_type.rs @@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; use crate::{ context::CommandContext, - exceptions::CommandSyntaxException, + errors::CommandSyntaxError, string_reader::StringReader, suggestion::{Suggestions, SuggestionsBuilder}, }; @@ -12,7 +12,7 @@ use crate::{ struct Boolean; impl ArgumentType for Boolean { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { Ok(Arc::new(reader.read_boolean()?)) } diff --git a/azalea-brigadier/src/arguments/double_argument_type.rs b/azalea-brigadier/src/arguments/double_argument_type.rs index 2e50d291..5b5d8cce 100644 --- a/azalea-brigadier/src/arguments/double_argument_type.rs +++ b/azalea-brigadier/src/arguments/double_argument_type.rs @@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; use crate::{ context::CommandContext, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, string_reader::StringReader, }; @@ -14,14 +14,14 @@ struct Double { } impl ArgumentType for Double { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { let start = reader.cursor; let result = reader.read_double()?; if let Some(minimum) = self.minimum && result < minimum { reader.cursor = start; - return Err(BuiltInExceptions::DoubleTooSmall { + return Err(BuiltInError::DoubleTooSmall { found: result, min: minimum, } @@ -31,7 +31,7 @@ impl ArgumentType for Double { && result > maximum { reader.cursor = start; - return Err(BuiltInExceptions::DoubleTooBig { + return Err(BuiltInError::DoubleTooBig { found: result, max: maximum, } diff --git a/azalea-brigadier/src/arguments/float_argument_type.rs b/azalea-brigadier/src/arguments/float_argument_type.rs index 23dc88a5..8ea3a417 100644 --- a/azalea-brigadier/src/arguments/float_argument_type.rs +++ b/azalea-brigadier/src/arguments/float_argument_type.rs @@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; use crate::{ context::CommandContext, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, string_reader::StringReader, }; @@ -14,14 +14,14 @@ struct Float { } impl ArgumentType for Float { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { let start = reader.cursor; let result = reader.read_float()?; if let Some(minimum) = self.minimum && result < minimum { reader.cursor = start; - return Err(BuiltInExceptions::FloatTooSmall { + return Err(BuiltInError::FloatTooSmall { found: result, min: minimum, } @@ -31,7 +31,7 @@ impl ArgumentType for Float { && result > maximum { reader.cursor = start; - return Err(BuiltInExceptions::FloatTooBig { + return Err(BuiltInError::FloatTooBig { found: result, max: maximum, } diff --git a/azalea-brigadier/src/arguments/integer_argument_type.rs b/azalea-brigadier/src/arguments/integer_argument_type.rs index b993d200..9cdb9c34 100644 --- a/azalea-brigadier/src/arguments/integer_argument_type.rs +++ b/azalea-brigadier/src/arguments/integer_argument_type.rs @@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; use crate::{ context::CommandContext, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, string_reader::StringReader, }; @@ -14,14 +14,14 @@ struct Integer { } impl ArgumentType for Integer { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { let start = reader.cursor; let result = reader.read_int()?; if let Some(minimum) = self.minimum && result < minimum { reader.cursor = start; - return Err(BuiltInExceptions::IntegerTooSmall { + return Err(BuiltInError::IntegerTooSmall { found: result, min: minimum, } @@ -31,7 +31,7 @@ impl ArgumentType for Integer { && result > maximum { reader.cursor = start; - return Err(BuiltInExceptions::IntegerTooBig { + return Err(BuiltInError::IntegerTooBig { found: result, max: maximum, } diff --git a/azalea-brigadier/src/arguments/long_argument_type.rs b/azalea-brigadier/src/arguments/long_argument_type.rs index 1e27cf9d..1d4b3c9b 100644 --- a/azalea-brigadier/src/arguments/long_argument_type.rs +++ b/azalea-brigadier/src/arguments/long_argument_type.rs @@ -3,7 +3,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; use crate::{ context::CommandContext, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, string_reader::StringReader, }; @@ -14,14 +14,14 @@ struct Long { } impl ArgumentType for Long { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { let start = reader.cursor; let result = reader.read_long()?; if let Some(minimum) = self.minimum && result < minimum { reader.cursor = start; - return Err(BuiltInExceptions::LongTooSmall { + return Err(BuiltInError::LongTooSmall { found: result, min: minimum, } @@ -31,7 +31,7 @@ impl ArgumentType for Long { && result > maximum { reader.cursor = start; - return Err(BuiltInExceptions::LongTooBig { + return Err(BuiltInError::LongTooBig { found: result, max: maximum, } diff --git a/azalea-brigadier/src/arguments/string_argument_type.rs b/azalea-brigadier/src/arguments/string_argument_type.rs index 96b9c998..bcb040d6 100644 --- a/azalea-brigadier/src/arguments/string_argument_type.rs +++ b/azalea-brigadier/src/arguments/string_argument_type.rs @@ -1,9 +1,7 @@ use std::{any::Any, sync::Arc}; use super::ArgumentType; -use crate::{ - context::CommandContext, exceptions::CommandSyntaxException, string_reader::StringReader, -}; +use crate::{context::CommandContext, errors::CommandSyntaxError, string_reader::StringReader}; pub enum StringArgument { /// Match up until the next space. @@ -16,7 +14,7 @@ pub enum StringArgument { } impl ArgumentType for StringArgument { - fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { let result = match self { StringArgument::SingleWord => reader.read_unquoted_string().to_string(), StringArgument::QuotablePhrase => reader.read_string()?, diff --git a/azalea-brigadier/src/builder/argument_builder.rs b/azalea-brigadier/src/builder/argument_builder.rs index bc7f0ac6..1731d44d 100644 --- a/azalea-brigadier/src/builder/argument_builder.rs +++ b/azalea-brigadier/src/builder/argument_builder.rs @@ -5,6 +5,7 @@ use parking_lot::RwLock; use super::{literal_argument_builder::Literal, required_argument_builder::Argument}; use crate::{ context::CommandContext, + errors::CommandSyntaxError, modifier::RedirectModifier, tree::{Command, CommandNode}, }; @@ -90,6 +91,16 @@ impl<S> ArgumentBuilder<S> { where F: Fn(&CommandContext<S>) -> i32 + Send + Sync + 'static, { + self.command = Some(Arc::new(move |ctx: &CommandContext<S>| Ok(f(ctx)))); + self + } + + /// Same as [`Self::executes`] but returns a `Result<i32, + /// CommandSyntaxError>`. + pub fn executes_result<F>(mut self, f: F) -> Self + where + F: Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync + 'static, + { self.command = Some(Arc::new(f)); self } diff --git a/azalea-brigadier/src/builder/required_argument_builder.rs b/azalea-brigadier/src/builder/required_argument_builder.rs index 7c0f1015..3fc33143 100644 --- a/azalea-brigadier/src/builder/required_argument_builder.rs +++ b/azalea-brigadier/src/builder/required_argument_builder.rs @@ -8,7 +8,7 @@ use super::argument_builder::{ArgumentBuilder, ArgumentBuilderType}; use crate::{ arguments::ArgumentType, context::CommandContext, - exceptions::CommandSyntaxException, + errors::CommandSyntaxError, string_reader::StringReader, suggestion::{SuggestionProvider, Suggestions, SuggestionsBuilder}, }; @@ -33,7 +33,7 @@ impl<S> Argument<S> { } } - pub fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxException> { + pub fn parse(&self, reader: &mut StringReader) -> Result<Arc<dyn Any>, CommandSyntaxError> { self.parser.parse(reader) } diff --git a/azalea-brigadier/src/command_dispatcher.rs b/azalea-brigadier/src/command_dispatcher.rs index 4a3b51d7..df732291 100644 --- a/azalea-brigadier/src/command_dispatcher.rs +++ b/azalea-brigadier/src/command_dispatcher.rs @@ -1,7 +1,7 @@ use std::{ cmp::Ordering, collections::{HashMap, HashSet}, - mem, ptr, + ptr, rc::Rc, sync::Arc, }; @@ -10,9 +10,10 @@ use parking_lot::RwLock; use crate::{ builder::argument_builder::ArgumentBuilder, - context::{CommandContext, CommandContextBuilder}, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + context::{CommandContextBuilder, ContextChain}, + errors::{BuiltInError, CommandSyntaxError}, parse_results::ParseResults, + result_consumer::{DefaultResultConsumer, ResultConsumer}, string_reader::StringReader, suggestion::{Suggestions, SuggestionsBuilder}, tree::CommandNode, @@ -30,12 +31,14 @@ where Self: Sync + Send, { pub root: Arc<RwLock<CommandNode<S>>>, + consumer: Box<dyn ResultConsumer<S> + Send + Sync>, } impl<S> CommandDispatcher<S> { pub fn new() -> Self { Self { root: Arc::new(RwLock::new(CommandNode::default())), + consumer: Box::new(DefaultResultConsumer), } } @@ -64,10 +67,10 @@ impl<S> CommandDispatcher<S> { node: &Arc<RwLock<CommandNode<S>>>, original_reader: &StringReader, context_so_far: CommandContextBuilder<'a, S>, - ) -> Result<ParseResults<'a, S>, CommandSyntaxException> { + ) -> Result<ParseResults<'a, S>, CommandSyntaxError> { let source = context_so_far.source.clone(); #[allow(clippy::mutable_key_type)] // this is fine because we don't mutate the key - let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxException>::new(); + let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxError>::new(); let mut potentials: Vec<ParseResults<S>> = vec![]; let cursor = original_reader.cursor(); @@ -83,7 +86,7 @@ impl<S> CommandDispatcher<S> { if let Err(ex) = parse_with_context_result { errors.insert( Rc::new((*child.read()).clone()), - BuiltInExceptions::DispatcherParseException { + BuiltInError::DispatcherParseException { message: ex.message(), } .create_with_context(&reader), @@ -94,8 +97,7 @@ impl<S> CommandDispatcher<S> { if reader.can_read() && reader.peek() != ' ' { errors.insert( Rc::new((*child.read()).clone()), - BuiltInExceptions::DispatcherExpectedArgumentSeparator - .create_with_context(&reader), + BuiltInError::DispatcherExpectedArgumentSeparator.create_with_context(&reader), ); reader.cursor = cursor; continue; @@ -179,11 +181,11 @@ impl<S> CommandDispatcher<S> { &self, input: impl Into<StringReader>, source: S, - ) -> Result<i32, CommandSyntaxException> { + ) -> Result<i32, CommandSyntaxError> { let input = input.into(); let parse = self.parse(input, source); - Self::execute_parsed(parse) + self.execute_parsed(parse) } pub fn add_paths( @@ -235,91 +237,26 @@ impl<S> CommandDispatcher<S> { } /// Executes a given pre-parsed command. - pub fn execute_parsed(parse: ParseResults<S>) -> Result<i32, CommandSyntaxException> { + pub fn execute_parsed(&self, parse: ParseResults<S>) -> Result<i32, CommandSyntaxError> { if parse.reader.can_read() { - if parse.exceptions.len() == 1 { - return Err(parse.exceptions.values().next().unwrap().clone()); - } - if parse.context.range.is_empty() { - return Err( - BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader) - ); - } - return Err( - BuiltInExceptions::DispatcherUnknownArgument.create_with_context(&parse.reader) - ); - } - let mut result = 0i32; - let mut successful_forks = 0; - let mut forked = false; - let mut found_command = false; - let command = parse.reader.string(); - let original = parse.context.build(command); - let mut contexts = vec![original]; - let mut next: Vec<CommandContext<S>> = vec![]; - - while !contexts.is_empty() { - for context in &contexts { - let child = &context.child; - if let Some(child) = child { - forked |= child.forks; - if child.has_nodes() { - found_command = true; - let modifier = &context.modifier; - if let Some(modifier) = modifier { - let results = modifier(context); - match results { - Ok(results) => { - if !results.is_empty() { - next.extend( - results.iter().map(|s| child.copy_for(s.clone())), - ); - } - } - _ => { - // TODO - // self.consumer.on_command_complete(context, false, 0); - if !forked { - return Err(results.err().unwrap()); - } - } - } - } else { - next.push(child.copy_for(context.source.clone())); - } - } - } else if let Some(context_command) = &context.command { - found_command = true; - - let value = context_command(context); - result += value; - // consumer.on_command_complete(context, true, value); - successful_forks += 1; - - // TODO: allow context_command to error and handle - // those errors - } - } - - // move next into contexts and clear next - mem::swap(&mut contexts, &mut next); - next.clear(); + return Err(if parse.exceptions.len() == 1 { + parse.exceptions.values().next().unwrap().clone() + } else if parse.context.range.is_empty() { + BuiltInError::DispatcherUnknownCommand.create_with_context(&parse.reader) + } else { + BuiltInError::DispatcherUnknownArgument.create_with_context(&parse.reader) + }); } - if !found_command { - // consumer.on_command_complete(original, false, 0); - return Err( - BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader) - ); - } + let command = parse.reader.string(); + let original = Rc::new(parse.context.build(command)); + let flat_context = ContextChain::try_flatten(original.clone()); + let Some(flat_context) = flat_context else { + self.consumer.on_command_complete(original, false, 0); + return Err(BuiltInError::DispatcherUnknownCommand.create_with_context(&parse.reader)); + }; - // TODO: this is not how vanilla does it but it works - Ok(if successful_forks >= 2 { - successful_forks - } else { - result - }) - // Ok(if forked { successful_forks } else { result }) + flat_context.execute_all(original.source().clone(), self.consumer.as_ref()) } pub fn get_all_usage( diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index 202d6f21..224f2d63 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -10,16 +10,16 @@ use crate::{ /// A built `CommandContextBuilder`. pub struct CommandContext<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<Arc<RedirectModifier<S>>>, - pub forks: bool, + pub(super) source: Arc<S>, + pub(super) input: String, + pub(super) arguments: HashMap<String, ParsedArgument>, + pub(super) command: Command<S>, + pub(super) root_node: Arc<RwLock<CommandNode<S>>>, + pub(super) nodes: Vec<ParsedCommandNode<S>>, + pub(super) range: StringRange, + pub(super) child: Option<Rc<CommandContext<S>>>, + pub(super) modifier: Option<Arc<RedirectModifier<S>>>, + pub(super) forks: bool, } impl<S> Clone for CommandContext<S> { @@ -59,8 +59,10 @@ impl<S> Debug for CommandContext<S> { impl<S> CommandContext<S> { pub fn copy_for(&self, source: Arc<S>) -> Self { if Arc::ptr_eq(&source, &self.source) { + // fast path return self.clone(); } + CommandContext { source, input: self.input.clone(), @@ -75,12 +77,56 @@ impl<S> CommandContext<S> { } } + pub fn child(&self) -> Option<&CommandContext<S>> { + self.child.as_ref().map(|c| c.as_ref()) + } + + pub fn last_child(&self) -> &CommandContext<S> { + let mut result = self; + while let Some(child) = result.child() { + result = child; + } + result + } + + pub fn command(&self) -> &Command<S> { + &self.command + } + + pub fn source(&self) -> &Arc<S> { + &self.source + } + + pub fn argument(&self, name: &str) -> Option<&dyn Any> { + let argument = self.arguments.get(name); + argument.map(|a| a.result.as_ref()) + } + + pub fn redirect_modifier(&self) -> Option<&RedirectModifier<S>> { + self.modifier.as_ref().map(|m| m.as_ref()) + } + + pub fn range(&self) -> &StringRange { + &self.range + } + + pub fn input(&self) -> &str { + &self.input + } + + pub fn root_node(&self) -> &Arc<RwLock<CommandNode<S>>> { + &self.root_node + } + + pub fn nodes(&self) -> &[ParsedCommandNode<S>] { + &self.nodes + } + pub fn has_nodes(&self) -> bool { !self.nodes.is_empty() } - pub fn argument(&self, name: &str) -> Option<Arc<dyn Any>> { - let argument = self.arguments.get(name); - argument.map(|a| a.result.clone()) + pub fn is_forked(&self) -> bool { + self.forks } } diff --git a/azalea-brigadier/src/context/context_chain.rs b/azalea-brigadier/src/context/context_chain.rs new file mode 100644 index 00000000..74fe6e01 --- /dev/null +++ b/azalea-brigadier/src/context/context_chain.rs @@ -0,0 +1,169 @@ +use std::{rc::Rc, sync::Arc}; + +use super::CommandContext; +use crate::{errors::CommandSyntaxError, result_consumer::ResultConsumer}; + +pub struct ContextChain<S> { + modifiers: Vec<Rc<CommandContext<S>>>, + executable: Rc<CommandContext<S>>, + next_stage_cache: Option<Rc<ContextChain<S>>>, +} + +impl<S> ContextChain<S> { + pub fn new(modifiers: Vec<Rc<CommandContext<S>>>, executable: Rc<CommandContext<S>>) -> Self { + if executable.command.is_none() { + panic!("Last command in chain must be executable"); + } + Self { + modifiers, + executable, + next_stage_cache: None, + } + } + + pub fn try_flatten(root_context: Rc<CommandContext<S>>) -> Option<Self> { + let mut modifiers = Vec::new(); + let mut current = root_context; + loop { + let child = current.child.clone(); + let Some(child) = child else { + // Last entry must be executable command + if current.command.is_none() { + return None; + } + + return Some(ContextChain::new(modifiers, current)); + }; + + modifiers.push(current); + current = child; + } + } + + pub fn run_modifier( + modifier: Rc<CommandContext<S>>, + source: Arc<S>, + result_consumer: &dyn ResultConsumer<S>, + forked_mode: bool, + ) -> Result<Vec<Arc<S>>, CommandSyntaxError> { + let source_modifier = modifier.redirect_modifier(); + let Some(source_modifier) = source_modifier else { + return Ok(vec![source]); + }; + + let context_to_use = Rc::new(modifier.copy_for(source)); + let err = match (source_modifier)(&context_to_use) { + Ok(res) => return Ok(res), + Err(e) => e, + }; + + result_consumer.on_command_complete(context_to_use, false, 0); + if forked_mode { + return Ok(vec![]); + } + Err(err) + } + + pub fn run_executable( + &self, + executable: Rc<CommandContext<S>>, + source: Arc<S>, + result_consumer: &dyn ResultConsumer<S>, + forked_mode: bool, + ) -> Result<i32, CommandSyntaxError> { + let context_to_use = Rc::new(executable.copy_for(source)); + let Some(command) = &executable.command else { + unimplemented!(); + }; + + let err = match (command)(&context_to_use) { + Ok(result) => { + result_consumer.on_command_complete(context_to_use, true, result); + return if forked_mode { Ok(1) } else { Ok(result) }; + } + Err(err) => err, + }; + + result_consumer.on_command_complete(context_to_use, false, 0); + if forked_mode { Ok(0) } else { Err(err) } + } + + pub fn execute_all( + &self, + source: Arc<S>, + result_consumer: &(dyn ResultConsumer<S>), + ) -> Result<i32, CommandSyntaxError> { + if self.modifiers.is_empty() { + return self.run_executable(self.executable.clone(), source, result_consumer, false); + } + + let mut forked_mode = false; + let mut current_sources = vec![source]; + + for modifier in &self.modifiers { + forked_mode |= modifier.is_forked(); + + let mut next_sources = Vec::new(); + for source_to_run in current_sources { + next_sources.extend(Self::run_modifier( + modifier.clone(), + source_to_run.clone(), + result_consumer, + forked_mode, + )?); + } + if next_sources.is_empty() { + return Ok(0); + } + current_sources = next_sources; + } + + let mut result = 0; + for execution_source in current_sources { + result += self.run_executable( + self.executable.clone(), + execution_source, + result_consumer, + forked_mode, + )?; + } + + Ok(result) + } + + pub fn stage(&self) -> Stage { + if self.modifiers.is_empty() { + Stage::Execute + } else { + Stage::Modify + } + } + + pub fn top_context(&self) -> Rc<CommandContext<S>> { + self.modifiers + .first() + .cloned() + .unwrap_or_else(|| self.executable.clone()) + } + + pub fn next_stage(&mut self) -> Option<Rc<ContextChain<S>>> { + let modifier_count = self.modifiers.len(); + if modifier_count == 0 { + return None; + } + + if self.next_stage_cache.is_none() { + self.next_stage_cache = Some(Rc::new(ContextChain::new( + self.modifiers[1..].to_vec(), + self.executable.clone(), + ))); + } + + self.next_stage_cache.clone() + } +} + +pub enum Stage { + Modify, + Execute, +} diff --git a/azalea-brigadier/src/context/mod.rs b/azalea-brigadier/src/context/mod.rs index 28e1a12e..815892bf 100644 --- a/azalea-brigadier/src/context/mod.rs +++ b/azalea-brigadier/src/context/mod.rs @@ -1,5 +1,6 @@ mod command_context; mod command_context_builder; +mod context_chain; mod parsed_argument; mod parsed_command_node; mod string_range; @@ -7,6 +8,7 @@ pub mod suggestion_context; pub use command_context::CommandContext; pub use command_context_builder::CommandContextBuilder; +pub use context_chain::ContextChain; pub use parsed_argument::ParsedArgument; pub use parsed_command_node::ParsedCommandNode; pub use string_range::StringRange; diff --git a/azalea-brigadier/src/exceptions/builtin_exceptions.rs b/azalea-brigadier/src/errors/builtin_errors.rs index bf2072c1..36803397 100644 --- a/azalea-brigadier/src/exceptions/builtin_exceptions.rs +++ b/azalea-brigadier/src/errors/builtin_errors.rs @@ -1,10 +1,10 @@ use std::fmt; -use super::command_syntax_exception::CommandSyntaxException; +use super::command_syntax_error::CommandSyntaxError; use crate::string_reader::StringReader; #[derive(Clone, PartialEq)] -pub enum BuiltInExceptions { +pub enum BuiltInError { DoubleTooSmall { found: f64, min: f64 }, DoubleTooBig { found: f64, max: f64 }, @@ -40,114 +40,114 @@ pub enum BuiltInExceptions { DispatcherParseException { message: String }, } -impl fmt::Debug for BuiltInExceptions { +impl fmt::Debug for BuiltInError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - BuiltInExceptions::DoubleTooSmall { found, min } => { + BuiltInError::DoubleTooSmall { found, min } => { write!(f, "Double must not be less than {min}, found {found}") } - BuiltInExceptions::DoubleTooBig { found, max } => { + BuiltInError::DoubleTooBig { found, max } => { write!(f, "Double must not be more than {max}, found {found}") } - BuiltInExceptions::FloatTooSmall { found, min } => { + BuiltInError::FloatTooSmall { found, min } => { write!(f, "Float must not be less than {min}, found {found}") } - BuiltInExceptions::FloatTooBig { found, max } => { + BuiltInError::FloatTooBig { found, max } => { write!(f, "Float must not be more than {max}, found {found}") } - BuiltInExceptions::IntegerTooSmall { found, min } => { + BuiltInError::IntegerTooSmall { found, min } => { write!(f, "Integer must not be less than {min}, found {found}") } - BuiltInExceptions::IntegerTooBig { found, max } => { + BuiltInError::IntegerTooBig { found, max } => { write!(f, "Integer must not be more than {max}, found {found}") } - BuiltInExceptions::LongTooSmall { found, min } => { + BuiltInError::LongTooSmall { found, min } => { write!(f, "Long must not be less than {min}, found {found}") } - BuiltInExceptions::LongTooBig { found, max } => { + BuiltInError::LongTooBig { found, max } => { write!(f, "Long must not be more than {max}, found {found}") } - BuiltInExceptions::LiteralIncorrect { expected } => { + BuiltInError::LiteralIncorrect { expected } => { write!(f, "Expected literal {expected}") } - BuiltInExceptions::ReaderExpectedStartOfQuote => { + BuiltInError::ReaderExpectedStartOfQuote => { write!(f, "Expected quote to start a string") } - BuiltInExceptions::ReaderExpectedEndOfQuote => { + BuiltInError::ReaderExpectedEndOfQuote => { write!(f, "Unclosed quoted string") } - BuiltInExceptions::ReaderInvalidEscape { character } => { + BuiltInError::ReaderInvalidEscape { character } => { write!(f, "Invalid escape sequence '{character}' in quoted string") } - BuiltInExceptions::ReaderInvalidBool { value } => { + BuiltInError::ReaderInvalidBool { value } => { write!( f, "Invalid bool, expected true or false but found '{value}'" ) } - BuiltInExceptions::ReaderInvalidInt { value } => { + BuiltInError::ReaderInvalidInt { value } => { write!(f, "Invalid Integer '{value}'") } - BuiltInExceptions::ReaderExpectedInt => { + BuiltInError::ReaderExpectedInt => { write!(f, "Expected Integer") } - BuiltInExceptions::ReaderInvalidLong { value } => { + BuiltInError::ReaderInvalidLong { value } => { write!(f, "Invalid long '{value}'") } - BuiltInExceptions::ReaderExpectedLong => { + BuiltInError::ReaderExpectedLong => { write!(f, "Expected long") } - BuiltInExceptions::ReaderInvalidDouble { value } => { + BuiltInError::ReaderInvalidDouble { value } => { write!(f, "Invalid double '{value}'") } - BuiltInExceptions::ReaderExpectedDouble => { + BuiltInError::ReaderExpectedDouble => { write!(f, "Expected double") } - BuiltInExceptions::ReaderInvalidFloat { value } => { + BuiltInError::ReaderInvalidFloat { value } => { write!(f, "Invalid Float '{value}'") } - BuiltInExceptions::ReaderExpectedFloat => { + BuiltInError::ReaderExpectedFloat => { write!(f, "Expected Float") } - BuiltInExceptions::ReaderExpectedBool => { + BuiltInError::ReaderExpectedBool => { write!(f, "Expected bool") } - BuiltInExceptions::ReaderExpectedSymbol { symbol } => { + BuiltInError::ReaderExpectedSymbol { symbol } => { write!(f, "Expected '{symbol}'") } - BuiltInExceptions::DispatcherUnknownCommand => { + BuiltInError::DispatcherUnknownCommand => { write!(f, "Unknown command") } - BuiltInExceptions::DispatcherUnknownArgument => { + BuiltInError::DispatcherUnknownArgument => { write!(f, "Incorrect argument for command") } - BuiltInExceptions::DispatcherExpectedArgumentSeparator => { + BuiltInError::DispatcherExpectedArgumentSeparator => { write!( f, "Expected whitespace to end one argument, but found trailing data" ) } - BuiltInExceptions::DispatcherParseException { message } => { + BuiltInError::DispatcherParseException { message } => { write!(f, "Could not parse command: {message}") } } } } -impl BuiltInExceptions { - pub fn create(self) -> CommandSyntaxException { +impl BuiltInError { + pub fn create(self) -> CommandSyntaxError { let message = format!("{self:?}"); - CommandSyntaxException::create(self, message) + CommandSyntaxError::create(self, message) } - pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxException { + pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxError { let message = format!("{self:?}"); - CommandSyntaxException::new(self, message, reader.string(), reader.cursor()) + CommandSyntaxError::new(self, message, reader.string(), reader.cursor()) } } diff --git a/azalea-brigadier/src/exceptions/command_syntax_exception.rs b/azalea-brigadier/src/errors/command_syntax_error.rs index c9b8134f..a476fec4 100644 --- a/azalea-brigadier/src/exceptions/command_syntax_exception.rs +++ b/azalea-brigadier/src/errors/command_syntax_error.rs @@ -1,13 +1,13 @@ use std::{ cmp, - fmt::{self, Write}, + fmt::{self, Debug, Write}, }; -use super::builtin_exceptions::BuiltInExceptions; +use super::builtin_errors::BuiltInError; #[derive(Clone, PartialEq)] -pub struct CommandSyntaxException { - pub type_: BuiltInExceptions, +pub struct CommandSyntaxError { + kind: BuiltInError, message: String, input: Option<String>, cursor: Option<usize>, @@ -15,19 +15,19 @@ pub struct CommandSyntaxException { const CONTEXT_AMOUNT: usize = 10; -impl CommandSyntaxException { - pub fn new(type_: BuiltInExceptions, message: String, input: &str, cursor: usize) -> Self { +impl CommandSyntaxError { + pub fn new(kind: BuiltInError, message: String, input: &str, cursor: usize) -> Self { Self { - type_, + kind, message, input: Some(input.to_string()), cursor: Some(cursor), } } - pub fn create(type_: BuiltInExceptions, message: String) -> Self { + pub fn create(kind: BuiltInError, message: String) -> Self { Self { - type_, + kind, message, input: None, cursor: None, @@ -40,9 +40,8 @@ impl CommandSyntaxException { if let Some(context) = context { write!( message, - " at position {}: {}", - self.cursor.unwrap_or(usize::MAX), - context + " at position {}: {context}", + self.cursor.unwrap_or(usize::MAX) ) .unwrap(); } @@ -74,8 +73,8 @@ impl CommandSyntaxException { None } - pub fn get_type(&self) -> &BuiltInExceptions { - &self.type_ + pub fn kind(&self) -> &BuiltInError { + &self.kind } pub fn input(&self) -> &Option<String> { @@ -87,7 +86,7 @@ impl CommandSyntaxException { } } -impl fmt::Debug for CommandSyntaxException { +impl Debug for CommandSyntaxError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.message()) } diff --git a/azalea-brigadier/src/errors/mod.rs b/azalea-brigadier/src/errors/mod.rs new file mode 100644 index 00000000..facebe5e --- /dev/null +++ b/azalea-brigadier/src/errors/mod.rs @@ -0,0 +1,5 @@ +mod builtin_errors; +mod command_syntax_error; + +pub use builtin_errors::BuiltInError; +pub use command_syntax_error::CommandSyntaxError; diff --git a/azalea-brigadier/src/exceptions/mod.rs b/azalea-brigadier/src/exceptions/mod.rs deleted file mode 100644 index 6b9c8d62..00000000 --- a/azalea-brigadier/src/exceptions/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod builtin_exceptions; -mod command_syntax_exception; - -pub use builtin_exceptions::BuiltInExceptions; -pub use command_syntax_exception::CommandSyntaxException; diff --git a/azalea-brigadier/src/lib.rs b/azalea-brigadier/src/lib.rs index 4f704d46..28f529f2 100644 --- a/azalea-brigadier/src/lib.rs +++ b/azalea-brigadier/src/lib.rs @@ -4,9 +4,10 @@ pub mod arguments; pub mod builder; pub mod command_dispatcher; pub mod context; -pub mod exceptions; +pub mod errors; pub mod modifier; pub mod parse_results; +pub mod result_consumer; pub mod string_reader; pub mod suggestion; pub mod tree; diff --git a/azalea-brigadier/src/modifier.rs b/azalea-brigadier/src/modifier.rs index bebdd0cb..aba5e95f 100644 --- a/azalea-brigadier/src/modifier.rs +++ b/azalea-brigadier/src/modifier.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::{context::CommandContext, exceptions::CommandSyntaxException}; +use crate::{context::CommandContext, errors::CommandSyntaxError}; pub type RedirectModifier<S> = - dyn Fn(&CommandContext<S>) -> Result<Vec<Arc<S>>, CommandSyntaxException> + Send + Sync; + dyn Fn(&CommandContext<S>) -> Result<Vec<Arc<S>>, CommandSyntaxError> + Send + Sync; diff --git a/azalea-brigadier/src/parse_results.rs b/azalea-brigadier/src/parse_results.rs index a2cefcf7..73de8d47 100644 --- a/azalea-brigadier/src/parse_results.rs +++ b/azalea-brigadier/src/parse_results.rs @@ -1,14 +1,14 @@ use std::{collections::HashMap, fmt::Debug, rc::Rc}; use crate::{ - context::CommandContextBuilder, exceptions::CommandSyntaxException, - string_reader::StringReader, tree::CommandNode, + context::CommandContextBuilder, errors::CommandSyntaxError, string_reader::StringReader, + tree::CommandNode, }; pub struct ParseResults<'a, S> { pub context: CommandContextBuilder<'a, S>, pub reader: StringReader, - pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxException>, + pub exceptions: HashMap<Rc<CommandNode<S>>, CommandSyntaxError>, } impl<S> Debug for ParseResults<'_, S> { diff --git a/azalea-brigadier/src/result_consumer.rs b/azalea-brigadier/src/result_consumer.rs new file mode 100644 index 00000000..fb9dd135 --- /dev/null +++ b/azalea-brigadier/src/result_consumer.rs @@ -0,0 +1,12 @@ +use std::rc::Rc; + +use crate::context::CommandContext; + +pub trait ResultConsumer<S> { + fn on_command_complete(&self, context: Rc<CommandContext<S>>, success: bool, result: i32); +} + +pub struct DefaultResultConsumer; +impl<S> ResultConsumer<S> for DefaultResultConsumer { + fn on_command_complete(&self, _context: Rc<CommandContext<S>>, _success: bool, _result: i32) {} +} diff --git a/azalea-brigadier/src/string_reader.rs b/azalea-brigadier/src/string_reader.rs index 963a2244..8dd41ed3 100644 --- a/azalea-brigadier/src/string_reader.rs +++ b/azalea-brigadier/src/string_reader.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use crate::exceptions::{BuiltInExceptions, CommandSyntaxException}; +use crate::errors::{BuiltInError, CommandSyntaxError}; #[derive(Clone)] pub struct StringReader { @@ -91,19 +91,19 @@ impl StringReader { } } - pub fn read_int(&mut self) -> Result<i32, CommandSyntaxException> { + pub fn read_int(&mut self) -> Result<i32, CommandSyntaxError> { let start = self.cursor; while self.can_read() && StringReader::is_allowed_number(self.peek()) { self.skip(); } let number = &self.string[start..self.cursor]; if number.is_empty() { - return Err(BuiltInExceptions::ReaderExpectedInt.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedInt.create_with_context(self)); } let result = i32::from_str(number); if result.is_err() { self.cursor = start; - return Err(BuiltInExceptions::ReaderInvalidInt { + return Err(BuiltInError::ReaderInvalidInt { value: number.to_string(), } .create_with_context(self)); @@ -112,19 +112,19 @@ impl StringReader { Ok(result.unwrap()) } - pub fn read_long(&mut self) -> Result<i64, CommandSyntaxException> { + pub fn read_long(&mut self) -> Result<i64, CommandSyntaxError> { let start = self.cursor; while self.can_read() && StringReader::is_allowed_number(self.peek()) { self.skip(); } let number = &self.string[start..self.cursor]; if number.is_empty() { - return Err(BuiltInExceptions::ReaderExpectedLong.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedLong.create_with_context(self)); } let result = i64::from_str(number); if result.is_err() { self.cursor = start; - return Err(BuiltInExceptions::ReaderInvalidLong { + return Err(BuiltInError::ReaderInvalidLong { value: number.to_string(), } .create_with_context(self)); @@ -133,19 +133,19 @@ impl StringReader { Ok(result.unwrap()) } - pub fn read_double(&mut self) -> Result<f64, CommandSyntaxException> { + pub fn read_double(&mut self) -> Result<f64, CommandSyntaxError> { let start = self.cursor; while self.can_read() && StringReader::is_allowed_number(self.peek()) { self.skip(); } let number = &self.string[start..self.cursor]; if number.is_empty() { - return Err(BuiltInExceptions::ReaderExpectedDouble.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedDouble.create_with_context(self)); } let result = f64::from_str(number); if result.is_err() { self.cursor = start; - return Err(BuiltInExceptions::ReaderInvalidDouble { + return Err(BuiltInError::ReaderInvalidDouble { value: number.to_string(), } .create_with_context(self)); @@ -154,19 +154,19 @@ impl StringReader { Ok(result.unwrap()) } - pub fn read_float(&mut self) -> Result<f32, CommandSyntaxException> { + pub fn read_float(&mut self) -> Result<f32, CommandSyntaxError> { let start = self.cursor; while self.can_read() && StringReader::is_allowed_number(self.peek()) { self.skip(); } let number = &self.string[start..self.cursor]; if number.is_empty() { - return Err(BuiltInExceptions::ReaderExpectedFloat.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedFloat.create_with_context(self)); } let result = f32::from_str(number); if result.is_err() { self.cursor = start; - return Err(BuiltInExceptions::ReaderInvalidFloat { + return Err(BuiltInError::ReaderInvalidFloat { value: number.to_string(), } .create_with_context(self)); @@ -193,22 +193,19 @@ impl StringReader { &self.string[start..self.cursor] } - pub fn read_quoted_string(&mut self) -> Result<String, CommandSyntaxException> { + pub fn read_quoted_string(&mut self) -> Result<String, CommandSyntaxError> { if !self.can_read() { return Ok(String::new()); } let next = self.peek(); if !StringReader::is_quoted_string_start(next) { - return Err(BuiltInExceptions::ReaderExpectedStartOfQuote.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedStartOfQuote.create_with_context(self)); } self.skip(); self.read_string_until(next) } - pub fn read_string_until( - &mut self, - terminator: char, - ) -> Result<String, CommandSyntaxException> { + pub fn read_string_until(&mut self, terminator: char) -> Result<String, CommandSyntaxError> { let mut result = String::new(); let mut escaped = false; while self.can_read() { @@ -219,7 +216,7 @@ impl StringReader { escaped = false; } else { self.cursor -= 1; - return Err(BuiltInExceptions::ReaderInvalidEscape { character: c } + return Err(BuiltInError::ReaderInvalidEscape { character: c } .create_with_context(self)); } } else if c == SYNTAX_ESCAPE { @@ -231,10 +228,10 @@ impl StringReader { } } - Err(BuiltInExceptions::ReaderExpectedEndOfQuote.create_with_context(self)) + Err(BuiltInError::ReaderExpectedEndOfQuote.create_with_context(self)) } - pub fn read_string(&mut self) -> Result<String, CommandSyntaxException> { + pub fn read_string(&mut self) -> Result<String, CommandSyntaxError> { if !self.can_read() { return Ok(String::new()); } @@ -246,11 +243,11 @@ impl StringReader { Ok(self.read_unquoted_string().to_string()) } - pub fn read_boolean(&mut self) -> Result<bool, CommandSyntaxException> { + pub fn read_boolean(&mut self) -> Result<bool, CommandSyntaxError> { let start = self.cursor; let value = self.read_string()?; if value.is_empty() { - return Err(BuiltInExceptions::ReaderExpectedBool.create_with_context(self)); + return Err(BuiltInError::ReaderExpectedBool.create_with_context(self)); } if value == "true" { @@ -259,15 +256,13 @@ impl StringReader { Ok(false) } else { self.cursor = start; - Err(BuiltInExceptions::ReaderInvalidBool { value }.create_with_context(self)) + Err(BuiltInError::ReaderInvalidBool { value }.create_with_context(self)) } } - pub fn expect(&mut self, c: char) -> Result<(), CommandSyntaxException> { + pub fn expect(&mut self, c: char) -> Result<(), CommandSyntaxError> { if !self.can_read() || self.peek() != c { - return Err( - BuiltInExceptions::ReaderExpectedSymbol { symbol: c }.create_with_context(self) - ); + return Err(BuiltInError::ReaderExpectedSymbol { symbol: c }.create_with_context(self)); } self.skip(); Ok(()) diff --git a/azalea-brigadier/src/tree/mod.rs b/azalea-brigadier/src/tree/mod.rs index 8181f817..bf53b4ff 100644 --- a/azalea-brigadier/src/tree/mod.rs +++ b/azalea-brigadier/src/tree/mod.rs @@ -14,13 +14,14 @@ use crate::{ required_argument_builder::Argument, }, context::{CommandContext, CommandContextBuilder, ParsedArgument, StringRange}, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, modifier::RedirectModifier, string_reader::StringReader, suggestion::{Suggestions, SuggestionsBuilder}, }; -pub type Command<S> = Option<Arc<dyn Fn(&CommandContext<S>) -> i32 + Send + Sync>>; +pub type Command<S> = + Option<Arc<dyn Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync>>; /// An ArgumentBuilder that has been built. #[non_exhaustive] @@ -149,7 +150,7 @@ impl<S> CommandNode<S> { &self, reader: &mut StringReader, context_builder: &mut CommandContextBuilder<S>, - ) -> Result<(), CommandSyntaxException> { + ) -> Result<(), CommandSyntaxError> { match self.value { ArgumentBuilderType::Argument(ref argument) => { let start = reader.cursor(); @@ -176,7 +177,7 @@ impl<S> CommandNode<S> { return Ok(()); } - Err(BuiltInExceptions::LiteralIncorrect { + Err(BuiltInError::LiteralIncorrect { expected: literal.value.clone(), } .create_with_context(reader)) diff --git a/azalea-brigadier/tests/bevy_app_usage.rs b/azalea-brigadier/tests/bevy_app_usage.rs index e962d7d1..d4660a5d 100644 --- a/azalea-brigadier/tests/bevy_app_usage.rs +++ b/azalea-brigadier/tests/bevy_app_usage.rs @@ -131,7 +131,7 @@ impl DispatchStorage { /// /// Spawns an entity with the [`SpawnedEntity`] component. fn command_spawn_entity(context: &CommandContext<WorldAccessor>) -> i32 { - context.source.lock().spawn(SpawnedEntity); + context.source().lock().spawn(SpawnedEntity); 0 } @@ -143,7 +143,7 @@ impl DispatchStorage { let num = get_integer(context, "entities").unwrap(); for _ in 0..num { - context.source.lock().spawn(SpawnedEntity); + context.source().lock().spawn(SpawnedEntity); } 0 diff --git a/azalea-brigadier/tests/command_dispatcher_test.rs b/azalea-brigadier/tests/command_dispatcher_test.rs index eecbf668..f04ddfdf 100644 --- a/azalea-brigadier/tests/command_dispatcher_test.rs +++ b/azalea-brigadier/tests/command_dispatcher_test.rs @@ -5,7 +5,7 @@ use azalea_brigadier::{ builder::{literal_argument_builder::literal, required_argument_builder::argument}, command_dispatcher::CommandDispatcher, context::CommandContext, - exceptions::{BuiltInExceptions, CommandSyntaxException}, + errors::{BuiltInError, CommandSyntaxError}, string_reader::StringReader, }; @@ -50,10 +50,7 @@ fn execute_unknown_command() { let execute_result = subject.execute("foo", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownCommand); assert_eq!(err.cursor().unwrap(), 0); } @@ -65,10 +62,7 @@ fn execute_impermissible_command() { let execute_result = subject.execute("foo", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownCommand); assert_eq!(err.cursor().unwrap(), 0); } @@ -80,10 +74,7 @@ fn execute_empty_command() { let execute_result = subject.execute("", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownCommand => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownCommand); assert_eq!(err.cursor().unwrap(), 0); } @@ -95,10 +86,7 @@ fn execute_unknown_subcommand() { let execute_result = subject.execute("foo bar", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownArgument); assert_eq!(err.cursor().unwrap(), 4); } @@ -110,10 +98,7 @@ fn execute_incorrect_literal() { let execute_result = subject.execute("foo baz", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownArgument); assert_eq!(err.cursor().unwrap(), 4); } @@ -130,10 +115,7 @@ fn execute_ambiguous_incorrect_argument() { let execute_result = subject.execute("foo unknown", &CommandSource {}); let err = execute_result.err().unwrap(); - match err.type_ { - BuiltInExceptions::DispatcherUnknownArgument => {} - _ => panic!("Unexpected error"), - } + assert_eq!(err.kind(), &BuiltInError::DispatcherUnknownArgument); assert_eq!(err.cursor().unwrap(), 4); } @@ -245,7 +227,7 @@ fn execute_redirected_multiple_times() { ); assert_eq!(*child2.unwrap().nodes[0].node.read(), *concrete_node.read()); - assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 42); + assert_eq!(subject.execute_parsed(parse).unwrap(), 42); } #[test] @@ -255,7 +237,7 @@ fn execute_redirected() { let source1 = Arc::new(CommandSource {}); let source2 = Arc::new(CommandSource {}); - let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Arc<CommandSource>>, CommandSyntaxException> { + let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Arc<CommandSource>>, CommandSyntaxError> { Ok(vec![source1.clone(), source2.clone()]) }; @@ -281,7 +263,7 @@ fn execute_redirected() { assert_eq!(*parent.nodes[0].node.read(), *concrete_node.read()); assert_eq!(*parent.source, CommandSource {}); - assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2); + assert_eq!(subject.execute_parsed(parse).unwrap(), 2); } #[test] @@ -297,10 +279,7 @@ fn execute_orphaned_subcommand() { let result = subject.execute("foo 5", &CommandSource {}); assert!(result.is_err()); let result = result.unwrap_err(); - assert_eq!( - *result.get_type(), - BuiltInExceptions::DispatcherUnknownCommand - ); + assert_eq!(*result.kind(), BuiltInError::DispatcherUnknownCommand); assert_eq!(result.cursor(), Some(5)); } @@ -327,10 +306,7 @@ fn parse_no_space_separator() { let result = subject.execute("foo$", &CommandSource {}); assert!(result.is_err()); let result = result.unwrap_err(); - assert_eq!( - *result.get_type(), - BuiltInExceptions::DispatcherUnknownCommand - ); + assert_eq!(*result.kind(), BuiltInError::DispatcherUnknownCommand); assert_eq!(result.cursor(), Some(0)); } @@ -348,7 +324,7 @@ fn execute_invalid_subcommand() { assert!(result.is_err()); let result = result.unwrap_err(); // this fails for some reason, i blame mojang - // assert_eq!(*result.get_type(), BuiltInExceptions::ReaderExpectedInt); + // assert_eq!(*result.get_type(), BuiltInError::ReaderExpectedInt); assert_eq!(result.cursor(), Some(4)); } diff --git a/azalea-brigadier/tests/string_reader_test.rs b/azalea-brigadier/tests/string_reader_test.rs index de605e99..3b70043b 100644 --- a/azalea-brigadier/tests/string_reader_test.rs +++ b/azalea-brigadier/tests/string_reader_test.rs @@ -1,4 +1,4 @@ -use azalea_brigadier::{exceptions::BuiltInExceptions, string_reader::StringReader}; +use azalea_brigadier::{errors::BuiltInError, string_reader::StringReader}; #[test] fn can_read() { @@ -222,7 +222,7 @@ fn read_quoted_string_no_open() { let result = reader.read_quoted_string(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedStartOfQuote); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedStartOfQuote); assert_eq!(e.cursor(), Some(0)); } } @@ -233,7 +233,7 @@ fn read_quoted_string_no_close() { let result = reader.read_quoted_string(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedEndOfQuote); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedEndOfQuote); assert_eq!(e.cursor(), Some(12)); } } @@ -245,8 +245,8 @@ fn read_quoted_string_invalid_escape() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidEscape { character: 'n' } + e.kind(), + &BuiltInError::ReaderInvalidEscape { character: 'n' } ); assert_eq!(e.cursor(), Some(7)); } @@ -259,8 +259,8 @@ fn read_quoted_string_invalid_quote_escape() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidEscape { character: '"' } + e.kind(), + &BuiltInError::ReaderInvalidEscape { character: '"' } ); assert_eq!(e.cursor(), Some(7)); } @@ -313,8 +313,8 @@ fn read_int_invalid() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidInt { + e.kind(), + &BuiltInError::ReaderInvalidInt { value: "12.34".to_string() } ); @@ -328,7 +328,7 @@ fn read_int_none() { let result = reader.read_int(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedInt); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedInt); assert_eq!(e.cursor(), Some(0)); } } @@ -372,8 +372,8 @@ fn read_long_invalid() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidLong { + e.kind(), + &BuiltInError::ReaderInvalidLong { value: "12.34".to_string() } ); @@ -387,7 +387,7 @@ fn read_long_none() { let result = reader.read_long(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedLong); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedLong); assert_eq!(e.cursor(), Some(0)); } } @@ -439,8 +439,8 @@ fn read_double_invalid() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidDouble { + e.kind(), + &BuiltInError::ReaderInvalidDouble { value: "12.34.56".to_string() } ); @@ -454,7 +454,7 @@ fn read_double_none() { let result = reader.read_double(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedDouble); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedDouble); assert_eq!(e.cursor(), Some(0)); } } @@ -506,8 +506,8 @@ fn read_float_invalid() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidFloat { + e.kind(), + &BuiltInError::ReaderInvalidFloat { value: "12.34.56".to_string() } ); @@ -521,7 +521,7 @@ fn read_float_none() { let result = reader.read_float(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedFloat); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedFloat); assert_eq!(e.cursor(), Some(0)); } } @@ -556,8 +556,8 @@ fn expect_incorrect() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderExpectedSymbol { symbol: 'a' } + e.kind(), + &BuiltInError::ReaderExpectedSymbol { symbol: 'a' } ); assert_eq!(e.cursor(), Some(0)); } @@ -570,8 +570,8 @@ fn expect_none() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderExpectedSymbol { symbol: 'a' } + e.kind(), + &BuiltInError::ReaderExpectedSymbol { symbol: 'a' } ); assert_eq!(e.cursor(), Some(0)); } @@ -591,8 +591,8 @@ fn read_boolean_incorrect() { assert!(result.is_err()); if let Err(e) = result { assert_eq!( - e.get_type(), - &BuiltInExceptions::ReaderInvalidBool { + e.kind(), + &BuiltInError::ReaderInvalidBool { value: "tuesday".to_string() } ); @@ -606,7 +606,7 @@ fn read_boolean_none() { let result = reader.read_boolean(); assert!(result.is_err()); if let Err(e) = result { - assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedBool); + assert_eq!(e.kind(), &BuiltInError::ReaderExpectedBool); assert_eq!(e.cursor(), Some(0)); } } |
