add documentation

This commit is contained in:
user622628252416 2024-08-20 12:09:25 +02:00
parent bfb3840b94
commit d221f8900f
4 changed files with 45 additions and 9 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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())

View File

@ -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 {