From d221f8900f9c4e7c74f303eb35c1ff93f04640ff Mon Sep 17 00:00:00 2001 From: user622628252416 Date: Tue, 20 Aug 2024 12:09:25 +0200 Subject: [PATCH] add documentation --- pumpkin/src/commands/dispatcher.rs | 12 ++++++++---- pumpkin/src/commands/mod.rs | 7 +++++-- pumpkin/src/commands/tree.rs | 6 ++++++ pumpkin/src/commands/tree_builder.rs | 29 +++++++++++++++++++++++++--- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index d65483352..82af621e3 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -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, tree: &CommandTree, mut raw_args: RawArgs) -> Result { + fn try_is_fitting_path(src: &mut CommandSender, path: Vec, tree: &CommandTree, mut raw_args: RawArgs) -> Result { let mut parsed_args: ConsumedArgs = HashMap::new(); diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 2774182ac..bf14bb491 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -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 = OnceLock::new(); +/// create [CommandDispatcher] instance for [DISPATCHER] fn dispatcher_init<'a>() -> CommandDispatcher<'a> { let mut map = HashMap::new(); diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 852ac21d9..52c406231 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -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; 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> = self.iter_paths() .map(|path| path.iter().map(|&i| &self.nodes[i].node_type).collect()) diff --git a/pumpkin/src/commands/tree_builder.rs b/pumpkin/src/commands/tree_builder.rs index efd298a3a..c3dac899c 100644 --- a/pumpkin/src/commands/tree_builder.rs +++ b/pumpkin/src/commands/tree_builder.rs @@ -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 {