use parking_lot::RwLock; use crate::{ context::CommandContext, modifier::RedirectModifier, tree::{Command, CommandNode}, }; use super::{literal_argument_builder::Literal, required_argument_builder::Argument}; use std::{fmt::Debug, sync::Arc}; #[derive(Debug, Clone)] pub enum ArgumentBuilderType { Literal(Literal), Argument(Argument), } /// A node that hasn't yet been built. pub struct ArgumentBuilder { arguments: CommandNode, command: Command, requirement: Arc) -> bool + Send + Sync>, target: Option>>>, forks: bool, modifier: Option>>, } /// A node that isn't yet built. impl ArgumentBuilder { pub fn new(value: ArgumentBuilderType) -> Self { Self { arguments: CommandNode { value, ..Default::default() }, command: None, requirement: Arc::new(|_| true), forks: false, modifier: None, target: None, } } /// Continue building this node with a child node. /// /// ``` /// # use azalea_brigadier::prelude::*; /// # let mut subject = CommandDispatcher::<()>::new(); /// literal("foo").then( /// literal("bar").executes(|ctx: &CommandContext<()>| 42) /// ) /// # ; /// ``` pub fn then(self, argument: ArgumentBuilder) -> Self { self.then_built(argument.build()) } /// Add an already built child node to this node. /// /// You should usually use [`Self::then`] instead. pub fn then_built(mut self, argument: CommandNode) -> Self { self.arguments.add_child(&Arc::new(RwLock::new(argument))); self } /// Set the command to be executed when this node is reached. If this is not /// present on a node, it is not a valid command. /// /// ``` /// # use azalea_brigadier::prelude::*; /// # let mut subject = CommandDispatcher::<()>::new(); /// # subject.register( /// literal("foo").executes(|ctx: &CommandContext<()>| 42) /// # ); /// ``` pub fn executes(mut self, f: F) -> Self where F: Fn(&CommandContext) -> i32 + Send + Sync + 'static, { self.command = Some(Arc::new(f)); self } /// Set the requirement for this node to be considered. If this is not /// present on a node, it is considered to always pass. /// /// ``` /// # use azalea_brigadier::prelude::*; /// # use std::sync::Arc; /// # pub struct CommandSource { /// # pub opped: bool, /// # } /// # let mut subject = CommandDispatcher::::new(); /// # subject.register( /// literal("foo") /// .requires(|s: Arc| s.opped) /// // ... /// # .executes(|ctx: &CommandContext| 42) /// # ); pub fn requires(mut self, requirement: F) -> Self where F: Fn(Arc) -> bool + Send + Sync + 'static, { self.requirement = Arc::new(requirement); self } pub fn redirect(self, target: Arc>>) -> Self { self.forward(target, None, false) } pub fn fork( self, target: Arc>>, modifier: Arc>, ) -> Self { self.forward(target, Some(modifier), true) } pub fn forward( mut self, target: Arc>>, modifier: Option>>, fork: bool, ) -> Self { if !self.arguments.children.is_empty() { panic!("Cannot forward a node with children"); } self.target = Some(target); self.modifier = modifier; self.forks = fork; self } /// Manually build this node into a [`CommandNode`]. You probably don't need /// to do this yourself. pub fn build(self) -> CommandNode { let mut result = CommandNode { value: self.arguments.value, command: self.command, requirement: self.requirement, redirect: self.target, modifier: self.modifier, forks: self.forks, arguments: Default::default(), children: Default::default(), literals: Default::default(), }; for argument in self.arguments.children.values() { result.add_child(argument); } result } } impl Debug for ArgumentBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ArgumentBuilder") .field("arguments", &self.arguments) // .field("command", &self.command) // .field("requirement", &self.requirement) .field("target", &self.target) .field("forks", &self.forks) // .field("modifier", &self.modifier) .finish() } }