Skip to main content

azalea_brigadier/context/
context_chain.rs

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