1use super::{
4 ArgumentType, BrigadierRuntime, CommandContext, CommandRequirement, CommandRuntime,
5 CommandSyntaxError, NodeId, RegistrationError, RegistrationErrorKind, SuggestionProvider,
6 node::{
7 CommandNodeData, CommandRedirect, CommandRedirectTarget, UnregisteredCommandNode,
8 merge_or_push,
9 },
10 runtime::{BrigadierExecutor, BrigadierModifier},
11};
12use crate::command::brigadier::node::ArgumentData;
13use std::sync::Arc;
14
15pub(crate) struct CommandNodeBuilder<S, R = BrigadierRuntime>
17where
18 R: CommandRuntime<S>,
19{
20 data: CommandNodeData<S, R::Argument>,
21 children: Vec<Self>,
22 executor: Option<Arc<R::Executor>>,
23 requirement: CommandRequirement<S>,
24 execution_requirement: CommandRequirement<S>,
25 redirect: Option<CommandRedirect<S, R>>,
26}
27
28pub(crate) struct CommandRequirementRoute<S> {
30 traversal: CommandRequirement<S>,
31 execution: CommandRequirement<S>,
32}
33
34impl<S> CommandRequirementRoute<S> {
35 pub(crate) const fn new(
37 traversal: CommandRequirement<S>,
38 execution: CommandRequirement<S>,
39 ) -> Self {
40 Self {
41 traversal,
42 execution,
43 }
44 }
45}
46
47impl<S> Clone for CommandRequirementRoute<S> {
48 fn clone(&self) -> Self {
49 Self {
50 traversal: self.traversal.clone(),
51 execution: self.execution.clone(),
52 }
53 }
54}
55
56#[derive(Clone, Debug, PartialEq, Eq)]
57struct RequirementRouteKey {
58 governing_scope: Option<usize>,
59 descendant_scopes: Vec<usize>,
60}
61
62#[derive(Clone, Copy)]
63struct ActiveRequirementScope<'path> {
64 index: usize,
65 remaining: &'path [Box<str>],
66}
67
68impl<S, R> Clone for CommandNodeBuilder<S, R>
69where
70 R: CommandRuntime<S>,
71 R::Argument: Clone,
72{
73 fn clone(&self) -> Self {
74 Self {
75 data: self.data.clone(),
76 children: self.children.clone(),
77 executor: self.executor.as_ref().map(Arc::clone),
78 requirement: self.requirement.clone(),
79 execution_requirement: self.execution_requirement.clone(),
80 redirect: self.redirect.clone(),
81 }
82 }
83}
84
85pub(crate) fn literal<S>(name: impl Into<Box<str>>) -> CommandNodeBuilder<S> {
87 CommandNodeBuilder::literal(name)
88}
89
90pub(crate) fn argument<S>(
92 name: impl Into<Box<str>>,
93 argument_type: ArgumentType,
94) -> CommandNodeBuilder<S> {
95 CommandNodeBuilder::argument(name, argument_type)
96}
97
98impl<S, R> CommandNodeBuilder<S, R>
99where
100 R: CommandRuntime<S>,
101{
102 pub(crate) fn literal(name: impl Into<Box<str>>) -> Self {
104 Self {
105 data: CommandNodeData::Literal(name.into()),
106 children: Vec::new(),
107 executor: None,
108 requirement: CommandRequirement::allow_all(),
109 execution_requirement: CommandRequirement::allow_all(),
110 redirect: None,
111 }
112 }
113
114 pub(crate) fn argument(name: impl Into<Box<str>>, argument_type: R::Argument) -> Self {
116 Self {
117 data: CommandNodeData::Argument(name.into(), ArgumentData::new(argument_type)),
118 children: Vec::new(),
119 executor: None,
120 requirement: CommandRequirement::allow_all(),
121 execution_requirement: CommandRequirement::allow_all(),
122 redirect: None,
123 }
124 }
125
126 #[must_use]
129 pub(crate) fn suggests(
130 self,
131 suggestion: impl SuggestionProvider<S, R::Argument> + 'static,
132 ) -> Self {
133 self.suggests_arc(Arc::new(suggestion))
134 }
135
136 #[must_use]
139 pub(crate) fn suggests_arc(
140 mut self,
141 suggestion: Arc<impl SuggestionProvider<S, R::Argument> + 'static>,
142 ) -> Self {
143 debug_assert!(
144 matches!(self.data, CommandNodeData::Argument(_, _)),
145 "suggests must be called on an argument node"
146 );
147 if let CommandNodeData::Argument(_, data) = &mut self.data {
148 data.custom_suggestions = Some(suggestion);
149 }
150 self
151 }
152
153 pub(crate) fn literal_name(&self) -> Option<&str> {
155 match &self.data {
156 CommandNodeData::Literal(name) => Some(name),
157 CommandNodeData::Root | CommandNodeData::Argument { .. } => None,
158 }
159 }
160
161 pub(crate) fn with_literal_name(mut self, name: impl Into<Box<str>>) -> Option<Self> {
163 let CommandNodeData::Literal(literal) = &mut self.data else {
164 return None;
165 };
166 *literal = name.into();
167 Some(self)
168 }
169
170 #[must_use]
172 pub(crate) fn then(mut self, child: Self) -> Self {
173 self.children.push(child);
174 self
175 }
176
177 #[must_use]
179 pub(crate) fn executes_with_executor(mut self, executor: Arc<R::Executor>) -> Self {
180 self.executor = Some(executor);
181 self
182 }
183
184 #[must_use]
186 pub(crate) fn requires(mut self, requirement: CommandRequirement<S>) -> Self {
187 self.requirement = requirement;
188 self
189 }
190
191 #[must_use]
193 pub(crate) fn also_requires(mut self, requirement: CommandRequirement<S>) -> Self
194 where
195 S: 'static,
196 {
197 self.requirement = self.requirement.and(requirement);
198 self
199 }
200
201 #[must_use]
203 pub(crate) fn also_requires_execution(mut self, requirement: CommandRequirement<S>) -> Self
204 where
205 S: 'static,
206 {
207 self.execution_requirement = self.execution_requirement.and(requirement);
208 self
209 }
210
211 pub(crate) fn literal_path_match_count(&self, path: &[Box<str>]) -> usize {
215 let Some((name, remaining)) = path.split_first() else {
216 return 0;
217 };
218 let mut matches = 0;
219 for child in &self.children {
220 let Some(literal) = child.literal_name() else {
221 matches += child.literal_path_match_count(path);
222 continue;
223 };
224 if literal != name.as_ref() {
225 continue;
226 }
227 if remaining.is_empty() {
228 matches += 1;
229 } else {
230 matches += child.literal_path_match_count(remaining);
231 }
232 }
233 matches
234 }
235
236 pub(crate) fn apply_scoped_requirements(
241 &mut self,
242 scope_paths: &[Vec<Box<str>>],
243 mut requirements_for: impl FnMut(Option<usize>, &[usize]) -> CommandRequirementRoute<S>,
244 ) where
245 S: 'static,
246 {
247 let active = scope_paths
248 .iter()
249 .enumerate()
250 .map(|(index, path)| ActiveRequirementScope {
251 index,
252 remaining: path,
253 })
254 .collect::<Vec<_>>();
255 let mut cache = Vec::new();
256 self.apply_scoped_requirements_inner(
257 None,
258 &active,
259 None,
260 &mut cache,
261 &mut requirements_for,
262 );
263 }
264
265 fn apply_scoped_requirements_inner<F>(
266 &mut self,
267 inherited_scope: Option<usize>,
268 active: &[ActiveRequirementScope<'_>],
269 parent_route: Option<&RequirementRouteKey>,
270 cache: &mut Vec<(RequirementRouteKey, CommandRequirementRoute<S>)>,
271 requirements_for: &mut F,
272 ) where
273 S: 'static,
274 F: FnMut(Option<usize>, &[usize]) -> CommandRequirementRoute<S>,
275 {
276 let governing_scope = active
277 .iter()
278 .find(|scope| scope.remaining.is_empty())
279 .map_or(inherited_scope, |scope| Some(scope.index));
280 let descendant_scopes = active
281 .iter()
282 .filter(|scope| !scope.remaining.is_empty())
283 .map(|scope| scope.index)
284 .collect::<Vec<_>>();
285 let route = RequirementRouteKey {
286 governing_scope,
287 descendant_scopes,
288 };
289 let requirements = cached_route_requirements(cache, &route, requirements_for);
290
291 if parent_route != Some(&route) {
292 self.requirement = self.requirement.clone().and(requirements.traversal);
293 }
294 if !route.descendant_scopes.is_empty() && self.executor.is_some() {
295 self.execution_requirement = self
296 .execution_requirement
297 .clone()
298 .and(requirements.execution);
299 }
300
301 for child in &mut self.children {
302 let child_active = if let Some(literal) = child.literal_name() {
303 active
304 .iter()
305 .filter_map(|scope| {
306 let (name, remaining) = scope.remaining.split_first()?;
307 (name.as_ref() == literal).then_some(ActiveRequirementScope {
308 index: scope.index,
309 remaining,
310 })
311 })
312 .collect::<Vec<_>>()
313 } else {
314 active
315 .iter()
316 .filter(|scope| {
317 !scope.remaining.is_empty()
318 && child.literal_path_match_count(scope.remaining) > 0
319 })
320 .copied()
321 .collect::<Vec<_>>()
322 };
323 child.apply_scoped_requirements_inner(
324 governing_scope,
325 &child_active,
326 Some(&route),
327 cache,
328 requirements_for,
329 );
330 }
331 }
332
333 #[must_use]
335 pub(crate) fn redirects(mut self, target: impl Into<CommandRedirectTarget>) -> Self {
336 self.redirect = Some(CommandRedirect::identity(target.into()));
337 self
338 }
339
340 #[must_use]
342 pub(crate) fn redirects_with_modifier(
343 mut self,
344 target: impl Into<CommandRedirectTarget>,
345 modifier: Arc<R::Modifier>,
346 forks: bool,
347 ) -> Self {
348 self.redirect = Some(CommandRedirect::with_modifier(
349 target.into(),
350 modifier,
351 forks,
352 ));
353 self
354 }
355
356 pub(super) fn normalize(self) -> Result<UnregisteredCommandNode<S, R>, RegistrationError> {
357 let mut children = Vec::new();
358 for child in self.children {
359 merge_or_push(&mut children, child.normalize()?)?;
360 }
361 if self.redirect.is_some() && !children.is_empty() {
362 return Err(RegistrationError::new(
363 RegistrationErrorKind::RedirectWithChildren {
364 name: self.data.name().into(),
365 },
366 ));
367 }
368
369 Ok(UnregisteredCommandNode {
370 data: self.data,
371 children,
372 executor: self.executor,
373 requirement: self.requirement,
374 execution_requirement: self.execution_requirement,
375 redirect: self.redirect,
376 })
377 }
378}
379
380fn cached_route_requirements<S, F>(
381 cache: &mut Vec<(RequirementRouteKey, CommandRequirementRoute<S>)>,
382 route: &RequirementRouteKey,
383 requirements_for: &mut F,
384) -> CommandRequirementRoute<S>
385where
386 F: FnMut(Option<usize>, &[usize]) -> CommandRequirementRoute<S>,
387{
388 if let Some((_, requirements)) = cache.iter().find(|(cached, _)| cached == route) {
389 return requirements.clone();
390 }
391 let requirements = requirements_for(route.governing_scope, &route.descendant_scopes);
392 cache.push((route.clone(), requirements.clone()));
393 requirements
394}
395
396impl<S> CommandNodeBuilder<S, BrigadierRuntime> {
397 #[must_use]
399 pub(crate) fn executes(
400 self,
401 executor: impl Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync + 'static,
402 ) -> Self {
403 let executor: Arc<BrigadierExecutor<S>> = Arc::new(executor);
404 self.executes_with_executor(executor)
405 }
406
407 #[must_use]
409 pub(crate) fn redirects_with(
410 self,
411 target: NodeId,
412 modifier: impl Fn(&CommandContext<S>) -> Result<S, CommandSyntaxError> + Send + Sync + 'static,
413 ) -> Self {
414 let modifier: Arc<BrigadierModifier<S>> =
415 Arc::new(move |context| modifier(context).map(|source| vec![source]));
416 self.redirects_with_modifier(target, modifier, false)
417 }
418
419 #[must_use]
421 pub(crate) fn forks(
422 self,
423 target: NodeId,
424 modifier: impl Fn(&CommandContext<S>) -> Result<Vec<S>, CommandSyntaxError>
425 + Send
426 + Sync
427 + 'static,
428 ) -> Self {
429 let modifier: Arc<BrigadierModifier<S>> = Arc::new(modifier);
430 self.redirects_with_modifier(target, modifier, true)
431 }
432}