azalea_brigadier/tree/
mod.rs

1use std::{
2    collections::{BTreeMap, HashMap},
3    fmt::{self, Debug},
4    hash::{Hash, Hasher},
5    ptr,
6    sync::Arc,
7};
8
9use parking_lot::RwLock;
10
11use crate::{
12    builder::{
13        argument_builder::ArgumentBuilderType, literal_argument_builder::Literal,
14        required_argument_builder::Argument,
15    },
16    context::{CommandContext, CommandContextBuilder, ParsedArgument, StringRange},
17    errors::{BuiltInError, CommandSyntaxError},
18    modifier::RedirectModifier,
19    string_reader::StringReader,
20    suggestion::{Suggestions, SuggestionsBuilder},
21};
22
23pub type Command<S> =
24    Option<Arc<dyn Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync>>;
25
26/// An ArgumentBuilder that has been built.
27#[non_exhaustive]
28pub struct CommandNode<S> {
29    pub value: ArgumentBuilderType<S>,
30
31    // this is a BTreeMap because children need to be ordered when getting command suggestions
32    pub children: BTreeMap<String, Arc<RwLock<CommandNode<S>>>>,
33    pub literals: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
34    pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
35
36    pub command: Command<S>,
37    pub requirement: Arc<dyn Fn(&S) -> bool + Send + Sync>,
38    pub redirect: Option<Arc<RwLock<CommandNode<S>>>>,
39    pub forks: bool,
40    pub modifier: Option<Arc<RedirectModifier<S>>>,
41}
42
43impl<S> Clone for CommandNode<S> {
44    fn clone(&self) -> Self {
45        Self {
46            value: self.value.clone(),
47            children: self.children.clone(),
48            literals: self.literals.clone(),
49            arguments: self.arguments.clone(),
50            command: self.command.clone(),
51            requirement: self.requirement.clone(),
52            redirect: self.redirect.clone(),
53            forks: self.forks,
54            modifier: self.modifier.clone(),
55        }
56    }
57}
58
59impl<S> CommandNode<S> {
60    /// Returns the value as a literal from this command node, assuming it's
61    /// already been checked.
62    ///
63    /// # Panics
64    ///
65    /// Will panic if this node is not a literal. Consider using a match
66    /// statement instead.
67    pub fn literal(&self) -> &Literal {
68        match self.value {
69            ArgumentBuilderType::Literal(ref literal) => literal,
70            _ => panic!("CommandNode::literal() called on non-literal node"),
71        }
72    }
73    /// Returns the value as an argument from this command node, assuming it's
74    /// already been checked.
75    ///
76    /// # Panics
77    ///
78    /// Will panic if this node is not an argument. Consider using a match
79    /// statement instead.
80    pub fn argument(&self) -> &Argument<S> {
81        match self.value {
82            ArgumentBuilderType::Argument(ref argument) => argument,
83            _ => panic!("CommandNode::argument() called on non-argument node"),
84        }
85    }
86
87    pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Arc<RwLock<CommandNode<S>>>> {
88        let literals = &self.literals;
89
90        if literals.is_empty() {
91            self.arguments.values().cloned().collect()
92        } else {
93            let cursor = input.cursor();
94            while input.can_read() && input.peek() != ' ' {
95                input.skip();
96            }
97            let text: String = input
98                .string()
99                .chars()
100                .skip(cursor)
101                .take(input.cursor() - cursor)
102                .collect();
103            input.cursor = cursor;
104            let literal = literals.get(&text);
105            if let Some(literal) = literal {
106                vec![literal.clone()]
107            } else {
108                self.arguments.values().cloned().collect()
109            }
110        }
111    }
112
113    pub fn can_use(&self, source: &S) -> bool {
114        (self.requirement)(source)
115    }
116
117    pub fn add_child(&mut self, node: &Arc<RwLock<CommandNode<S>>>) {
118        let child = self.children.get(node.read().name());
119        if let Some(child) = child {
120            // We've found something to merge onto
121            if let Some(command) = &node.read().command {
122                child.write().command = Some(command.clone());
123            }
124            for grandchild in node.read().children.values() {
125                child.write().add_child(grandchild);
126            }
127        } else {
128            self.children
129                .insert(node.read().name().to_string(), node.clone());
130            match &node.read().value {
131                ArgumentBuilderType::Literal(literal) => {
132                    self.literals.insert(literal.value.clone(), node.clone());
133                }
134                ArgumentBuilderType::Argument(argument) => {
135                    self.arguments.insert(argument.name.clone(), node.clone());
136                }
137            }
138        }
139    }
140
141    pub fn name(&self) -> &str {
142        match &self.value {
143            ArgumentBuilderType::Argument(argument) => &argument.name,
144            ArgumentBuilderType::Literal(literal) => &literal.value,
145        }
146    }
147
148    pub fn usage_text(&self) -> String {
149        match &self.value {
150            ArgumentBuilderType::Argument(argument) => format!("<{}>", argument.name),
151            ArgumentBuilderType::Literal(literal) => literal.value.to_owned(),
152        }
153    }
154
155    pub fn child(&self, name: &str) -> Option<Arc<RwLock<CommandNode<S>>>> {
156        self.children.get(name).cloned()
157    }
158
159    pub fn parse_with_context(
160        &self,
161        reader: &mut StringReader,
162        context_builder: &mut CommandContextBuilder<S>,
163    ) -> Result<(), CommandSyntaxError> {
164        match self.value {
165            ArgumentBuilderType::Argument(ref argument) => {
166                let start = reader.cursor();
167                let result = argument.parse(reader)?;
168                let parsed = ParsedArgument {
169                    range: StringRange::between(start, reader.cursor()),
170                    result,
171                };
172
173                context_builder.with_argument(&argument.name, parsed.clone());
174                context_builder.with_node(Arc::new(RwLock::new(self.clone())), parsed.range);
175
176                Ok(())
177            }
178            ArgumentBuilderType::Literal(ref literal) => {
179                let start = reader.cursor();
180                let end = self.parse(reader);
181
182                if let Some(end) = end {
183                    context_builder.with_node(
184                        Arc::new(RwLock::new(self.clone())),
185                        StringRange::between(start, end),
186                    );
187                    return Ok(());
188                }
189
190                Err(BuiltInError::LiteralIncorrect {
191                    expected: literal.value.clone(),
192                }
193                .create_with_context(reader))
194            }
195        }
196    }
197
198    fn parse(&self, reader: &mut StringReader) -> Option<usize> {
199        match self.value {
200            ArgumentBuilderType::Argument(_) => {
201                panic!("Can't parse argument.")
202            }
203            ArgumentBuilderType::Literal(ref literal) => {
204                let start = reader.cursor();
205                if reader.can_read_length(literal.value.len()) {
206                    let end = start + literal.value.len();
207                    if reader
208                        .string()
209                        .get(start..end)
210                        .expect("Couldn't slice reader correctly?")
211                        == literal.value
212                    {
213                        reader.cursor = end;
214                        if !reader.can_read() || reader.peek() == ' ' {
215                            return Some(end);
216                        } else {
217                            reader.cursor = start;
218                        }
219                    }
220                }
221            }
222        }
223        None
224    }
225
226    pub fn list_suggestions(
227        &self,
228        context: CommandContext<S>,
229        builder: SuggestionsBuilder,
230    ) -> Suggestions {
231        match &self.value {
232            ArgumentBuilderType::Literal(literal) => {
233                if literal
234                    .value
235                    .to_lowercase()
236                    .starts_with(builder.remaining_lowercase())
237                {
238                    builder.suggest(&literal.value).build()
239                } else {
240                    Suggestions::default()
241                }
242            }
243            ArgumentBuilderType::Argument(argument) => argument.list_suggestions(context, builder),
244        }
245    }
246}
247
248impl<S> Debug for CommandNode<S> {
249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250        f.debug_struct("CommandNode")
251            // .field("value", &self.value)
252            .field("children", &self.children)
253            .field("command", &self.command.is_some())
254            // .field("requirement", &self.requirement)
255            .field("redirect", &self.redirect)
256            .field("forks", &self.forks)
257            // .field("modifier", &self.modifier)
258            .finish()
259    }
260}
261
262impl<S> Default for CommandNode<S> {
263    fn default() -> Self {
264        Self {
265            value: ArgumentBuilderType::Literal(Literal::default()),
266
267            children: BTreeMap::new(),
268            literals: HashMap::new(),
269            arguments: HashMap::new(),
270
271            command: None,
272            requirement: Arc::new(|_| true),
273            redirect: None,
274            forks: false,
275            modifier: None,
276        }
277    }
278}
279
280impl<S> Hash for CommandNode<S> {
281    fn hash<H: Hasher>(&self, state: &mut H) {
282        // hash the children
283        for (k, v) in &self.children {
284            k.hash(state);
285            v.read().hash(state);
286        }
287        // i hope this works because if doesn't then that'll be a problem
288        ptr::hash(&self.command, state);
289    }
290}
291
292impl<S> PartialEq for CommandNode<S> {
293    fn eq(&self, other: &Self) -> bool {
294        if self.children.len() != other.children.len() {
295            return false;
296        }
297        for (k, v) in &self.children {
298            let other_child = other.children.get(k).unwrap();
299            if !Arc::ptr_eq(v, other_child) {
300                return false;
301            }
302        }
303
304        match &self.command {
305            Some(selfexecutes) => {
306                // idk how to do this better since we can't compare `dyn Fn`s
307                match &other.command {
308                    Some(otherexecutes) =>
309                    {
310                        #[allow(ambiguous_wide_pointer_comparisons)]
311                        if !Arc::ptr_eq(selfexecutes, otherexecutes) {
312                            return false;
313                        }
314                    }
315                    _ => {
316                        return false;
317                    }
318                }
319            }
320            _ => {
321                if other.command.is_some() {
322                    return false;
323                }
324            }
325        }
326        true
327    }
328}
329impl<S> Eq for CommandNode<S> {}