add documentation
This commit is contained in:
parent
bfb3840b94
commit
d221f8900f
@ -18,7 +18,10 @@ pub(crate) struct CommandDispatcher<'a> {
|
||||
pub(crate) commands: HashMap<&'a str, CommandTree<'a>>
|
||||
}
|
||||
|
||||
/// Stores registered [CommandTree]s and dispatches commands to them.
|
||||
impl <'a> CommandDispatcher<'a> {
|
||||
|
||||
/// Execute a command using its corresponding [CommandTree].
|
||||
pub(crate) fn dispatch(&'a self, src: &mut CommandSender, cmd: &str) -> Result<(), String> {
|
||||
|
||||
let mut parts = cmd.split_ascii_whitespace();
|
||||
@ -27,8 +30,9 @@ impl <'a> CommandDispatcher<'a> {
|
||||
|
||||
let tree = self.commands.get(key).ok_or("Command not found")?;
|
||||
|
||||
// try paths until fitting path is found
|
||||
for path in tree.iter_paths() {
|
||||
match Self::try_path(src, path, tree, raw_args.clone()) {
|
||||
match Self::try_is_fitting_path(src, path, tree, raw_args.clone()) {
|
||||
Err(InvalidConsumptionError(s)) => {
|
||||
println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed");
|
||||
return Err("Internal Error (See logs for details)".into())
|
||||
@ -37,8 +41,8 @@ impl <'a> CommandDispatcher<'a> {
|
||||
println!("Error while parsing command \"{cmd}\": a requirement that was expected was not met.");
|
||||
return Err("Internal Error (See logs for details)".into())
|
||||
},
|
||||
Ok(fitting_path) => {
|
||||
if fitting_path { return Ok(()) }
|
||||
Ok(is_fitting_path) => {
|
||||
if is_fitting_path { return Ok(()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +50,7 @@ impl <'a> CommandDispatcher<'a> {
|
||||
Err(format!("Invalid Syntax. Usage:{}", tree.paths_formatted(key)))
|
||||
}
|
||||
|
||||
fn try_path(src: &mut CommandSender, path: Vec<usize>, tree: &CommandTree, mut raw_args: RawArgs) -> Result<bool, InvalidTreeError> {
|
||||
fn try_is_fitting_path(src: &mut CommandSender, path: Vec<usize>, tree: &CommandTree, mut raw_args: RawArgs) -> Result<bool, InvalidTreeError> {
|
||||
|
||||
let mut parsed_args: ConsumedArgs = HashMap::new();
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ mod tree;
|
||||
mod tree_builder;
|
||||
mod dispatcher;
|
||||
mod arg_player;
|
||||
mod cmd_teleport;
|
||||
mod cmd_help;
|
||||
|
||||
pub enum CommandSender<'a> {
|
||||
@ -63,9 +62,13 @@ impl<'a> CommandSender<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// todo: reconsider using constant
|
||||
/// todo: reconsider using constant
|
||||
///
|
||||
/// Central point from which commands are dispatched. Should always be initialized using
|
||||
/// [dispatcher_init].
|
||||
const DISPATCHER: OnceLock<CommandDispatcher> = OnceLock::new();
|
||||
|
||||
/// create [CommandDispatcher] instance for [DISPATCHER]
|
||||
fn dispatcher_init<'a>() -> CommandDispatcher<'a> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
|
||||
@ -2,11 +2,15 @@ use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::tree_builder::{argument, NonLeafNodeBuilder};
|
||||
|
||||
/// see [argument]
|
||||
pub(crate) type RawArgs<'a> = Vec<&'a str>;
|
||||
|
||||
/// see [argument] and [CommandTree::execute]/[NonLeafNodeBuilder::execute]
|
||||
pub(crate) type ConsumedArgs<'a> = HashMap<&'a str, String>;
|
||||
|
||||
/// see [argument]
|
||||
pub(crate) type ArgumentConsumer<'a> = fn(&CommandSender, &mut RawArgs) -> Option<String>;
|
||||
|
||||
pub(crate) struct Node<'a> {
|
||||
@ -51,6 +55,8 @@ impl <'a> CommandTree<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// format possible paths as [String], using ```name``` as the command name
|
||||
pub(crate) fn paths_formatted(&'a self, name: &str) -> String {
|
||||
let paths: Vec<Vec<&NodeType>> = self.iter_paths()
|
||||
.map(|path| path.iter().map(|&i| &self.nodes[i].node_type).collect())
|
||||
|
||||
@ -3,6 +3,8 @@ use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::tree::{ArgumentConsumer, ConsumedArgs, Node, NodeType, CommandTree};
|
||||
|
||||
impl <'a> CommandTree<'a> {
|
||||
|
||||
/// Add a child [Node] to the root of this [CommandTree].
|
||||
pub fn with_child(mut self, child: impl NodeBuilder<'a>) -> Self {
|
||||
let node = child.build(&mut self);
|
||||
self.children.push(self.nodes.len());
|
||||
@ -19,6 +21,12 @@ impl <'a> CommandTree<'a> {
|
||||
}
|
||||
|
||||
/// Executes if a command terminates at this [Node], i.e. without any arguments.
|
||||
///
|
||||
/// [ConsumedArgs] maps the names of all
|
||||
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
||||
/// desired type.
|
||||
///
|
||||
/// Also see [NonLeafNodeBuilder::execute].
|
||||
pub fn execute(mut self, run: &'a dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError>) -> Self {
|
||||
let node = Node {
|
||||
node_type: NodeType::ExecuteLeaf {
|
||||
@ -81,12 +89,20 @@ impl <'a>NodeBuilder<'a> for NonLeafNodeBuilder<'a> {
|
||||
}
|
||||
|
||||
impl <'a>NonLeafNodeBuilder<'a> {
|
||||
|
||||
/// Add a child [Node] to this one.
|
||||
pub fn with_child(mut self, child: NonLeafNodeBuilder<'a>) -> Self {
|
||||
self.child_nodes.push(child);
|
||||
self
|
||||
}
|
||||
|
||||
/// Executes if a command terminates at this [Node].
|
||||
///
|
||||
/// [ConsumedArgs] maps the names of all
|
||||
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
||||
/// desired type.
|
||||
///
|
||||
/// Also see [CommandTree::execute].
|
||||
pub fn execute(mut self, run: &'a dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError>) -> Self {
|
||||
self.leaf_nodes.push(LeafNodeBuilder {
|
||||
node_type: NodeType::ExecuteLeaf {
|
||||
@ -109,8 +125,14 @@ pub fn literal(string: &str) -> NonLeafNodeBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// ```name``` identifies this argument.
|
||||
/// ```consumer: [ArgumentConsumer]``` has the purpose of validating arguments. Conversion may start here, as long as the result remains a [String] (e.g. convert offset to absolute position actual coordinates). It must remove consumed arg(s) from [RawArgs] and return them. It must return None if [RawArgs] are invalid. [RawArgs] is reversed, so [Vec::pop] can be used to obtain args in ltr order.
|
||||
/// ```name``` identifies this argument in [ConsumedArgs].
|
||||
///
|
||||
/// ```consumer: ArgumentConsumer``` has the purpose of validating arguments. Conversion may start
|
||||
/// here, as long as the result remains a [String] (e.g. convert offset to absolute position actual
|
||||
/// coordinates), because the result of this function will be passed to following
|
||||
/// [NonLeafNodeBuilder::execute] nodes in a [ConsumedArgs] instance. It must remove consumed arg(s)
|
||||
/// from [RawArgs] and return them. It must return None if [RawArgs] are invalid. [RawArgs] is
|
||||
/// reversed, so [Vec::pop] can be used to obtain args in ltr order.
|
||||
pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBuilder<'a> {
|
||||
NonLeafNodeBuilder {
|
||||
node_type: NodeType::Argument {
|
||||
@ -122,7 +144,8 @@ pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBui
|
||||
}
|
||||
}
|
||||
|
||||
/// ```predicate``` should return ```false``` if requirement for reaching following [Node]s is not met.
|
||||
/// ```predicate``` should return ```false``` if requirement for reaching following [Node]s is not
|
||||
/// met.
|
||||
pub fn require(predicate: &dyn Fn(&CommandSender) -> bool) -> NonLeafNodeBuilder {
|
||||
NonLeafNodeBuilder {
|
||||
node_type: NodeType::Require {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user