Pumpkin/pumpkin/src/command/tree.rs
2024-11-28 21:52:55 +01:00

111 lines
2.9 KiB
Rust

use super::{args::ArgumentConsumer, CommandExecutor};
use crate::command::CommandSender;
use std::{collections::VecDeque, fmt::Debug};
/// see [`crate::commands::tree_builder::argument`]
pub type RawArgs<'a> = Vec<&'a str>;
#[derive(Debug)]
pub struct Node<'a> {
pub(crate) children: Vec<usize>,
pub(crate) node_type: NodeType<'a>,
}
pub enum NodeType<'a> {
ExecuteLeaf {
executor: &'a dyn CommandExecutor,
},
Literal {
string: &'a str,
},
Argument {
name: &'a str,
consumer: &'a dyn ArgumentConsumer,
},
Require {
predicate: &'a (dyn Fn(&CommandSender) -> bool + Sync),
},
}
impl Debug for NodeType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ExecuteLeaf { .. } => f
.debug_struct("ExecuteLeaf")
.field("executor", &"..")
.finish(),
Self::Literal { string } => f.debug_struct("Literal").field("string", string).finish(),
Self::Argument { name, .. } => f
.debug_struct("Argument")
.field("name", name)
.field("consumer", &"..")
.finish(),
Self::Require { .. } => f.debug_struct("Require").field("predicate", &"..").finish(),
}
}
}
pub enum Command<'a> {
Tree(CommandTree<'a>),
Alias(&'a str),
}
#[derive(Debug)]
pub struct CommandTree<'a> {
pub(crate) nodes: Vec<Node<'a>>,
pub(crate) children: Vec<usize>,
pub(crate) names: Vec<&'a str>,
pub(crate) description: &'a str,
}
impl<'a> CommandTree<'a> {
/// iterate over all possible paths that end in a [`NodeType::ExecuteLeaf`]
pub(crate) fn iter_paths(&'a self) -> impl Iterator<Item = Vec<usize>> + 'a {
let mut todo = VecDeque::<(usize, usize)>::new();
// add root's children
todo.extend(self.children.iter().map(|&i| (0, i)));
TraverseAllPathsIter::<'a> {
tree: self,
path: Vec::<usize>::new(),
todo,
}
}
}
struct TraverseAllPathsIter<'a> {
tree: &'a CommandTree<'a>,
path: Vec<usize>,
/// (depth, i)
todo: VecDeque<(usize, usize)>,
}
impl Iterator for TraverseAllPathsIter<'_> {
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (depth, i) = self.todo.pop_front()?;
let node = &self.tree.nodes[i];
// add new children to front
self.todo.reserve(node.children.len());
node.children
.iter()
.rev()
.for_each(|&c| self.todo.push_front((depth + 1, c)));
// update path
while self.path.len() > depth {
self.path.pop();
}
self.path.push(i);
if let NodeType::ExecuteLeaf { .. } = node.node_type {
return Some(self.path.clone());
}
}
}
}