azalea_brigadier/context/
context_chain.rs

1use std::{rc::Rc, sync::Arc};
2
3use super::CommandContext;
4use crate::{errors::CommandSyntaxError, result_consumer::ResultConsumer};
5
6pub struct ContextChain<S> {
7    modifiers: Vec<Rc<CommandContext<S>>>,
8    executable: Rc<CommandContext<S>>,
9    next_stage_cache: Option<Rc<ContextChain<S>>>,
10}
11
12impl<S> ContextChain<S> {
13    pub fn new(modifiers: Vec<Rc<CommandContext<S>>>, executable: Rc<CommandContext<S>>) -> Self {
14        if executable.command.is_none() {
15            panic!("Last command in chain must be executable");
16        }
17        Self {
18            modifiers,
19            executable,
20            next_stage_cache: None,
21        }
22    }
23
24    pub fn try_flatten(root_context: Rc<CommandContext<S>>) -> Option<Self> {
25        let mut modifiers = Vec::new();
26        let mut current = root_context;
27        loop {
28            let child = current.child.clone();
29            let Some(child) = child else {
30                // Last entry must be executable command
31                current.command.as_ref()?;
32
33                return Some(ContextChain::new(modifiers, current));
34            };
35
36            modifiers.push(current);
37            current = child;
38        }
39    }
40
41    pub fn run_modifier(
42        modifier: Rc<CommandContext<S>>,
43        source: Arc<S>,
44        result_consumer: &dyn ResultConsumer<S>,
45        forked_mode: bool,
46    ) -> Result<Vec<Arc<S>>, CommandSyntaxError> {
47        let source_modifier = modifier.redirect_modifier();
48        let Some(source_modifier) = source_modifier else {
49            return Ok(vec![source]);
50        };
51
52        let context_to_use = Rc::new(modifier.copy_for(source));
53        let err = match (source_modifier)(&context_to_use) {
54            Ok(res) => return Ok(res),
55            Err(e) => e,
56        };
57
58        result_consumer.on_command_complete(context_to_use, false, 0);
59        if forked_mode {
60            return Ok(vec![]);
61        }
62        Err(err)
63    }
64
65    pub fn run_executable(
66        &self,
67        executable: Rc<CommandContext<S>>,
68        source: Arc<S>,
69        result_consumer: &dyn ResultConsumer<S>,
70        forked_mode: bool,
71    ) -> Result<i32, CommandSyntaxError> {
72        let context_to_use = Rc::new(executable.copy_for(source));
73        let Some(command) = &executable.command else {
74            unimplemented!();
75        };
76
77        let err = match (command)(&context_to_use) {
78            Ok(result) => {
79                result_consumer.on_command_complete(context_to_use, true, result);
80                return if forked_mode { Ok(1) } else { Ok(result) };
81            }
82            Err(err) => err,
83        };
84
85        result_consumer.on_command_complete(context_to_use, false, 0);
86        if forked_mode { Ok(0) } else { Err(err) }
87    }
88
89    pub fn execute_all(
90        &self,
91        source: Arc<S>,
92        result_consumer: &dyn ResultConsumer<S>,
93    ) -> Result<i32, CommandSyntaxError> {
94        if self.modifiers.is_empty() {
95            return self.run_executable(self.executable.clone(), source, result_consumer, false);
96        }
97
98        let mut forked_mode = false;
99        let mut current_sources = vec![source];
100
101        for modifier in &self.modifiers {
102            forked_mode |= modifier.is_forked();
103
104            let mut next_sources = Vec::new();
105            for source_to_run in current_sources {
106                next_sources.extend(Self::run_modifier(
107                    modifier.clone(),
108                    source_to_run.clone(),
109                    result_consumer,
110                    forked_mode,
111                )?);
112            }
113            if next_sources.is_empty() {
114                return Ok(0);
115            }
116            current_sources = next_sources;
117        }
118
119        let mut result = 0;
120        for execution_source in current_sources {
121            result += self.run_executable(
122                self.executable.clone(),
123                execution_source,
124                result_consumer,
125                forked_mode,
126            )?;
127        }
128
129        Ok(result)
130    }
131
132    pub fn stage(&self) -> Stage {
133        if self.modifiers.is_empty() {
134            Stage::Execute
135        } else {
136            Stage::Modify
137        }
138    }
139
140    pub fn top_context(&self) -> Rc<CommandContext<S>> {
141        self.modifiers
142            .first()
143            .cloned()
144            .unwrap_or_else(|| self.executable.clone())
145    }
146
147    pub fn next_stage(&mut self) -> Option<Rc<ContextChain<S>>> {
148        let modifier_count = self.modifiers.len();
149        if modifier_count == 0 {
150            return None;
151        }
152
153        if self.next_stage_cache.is_none() {
154            self.next_stage_cache = Some(Rc::new(ContextChain::new(
155                self.modifiers[1..].to_vec(),
156                self.executable.clone(),
157            )));
158        }
159
160        self.next_stage_cache.clone()
161    }
162}
163
164pub enum Stage {
165    Modify,
166    Execute,
167}