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                match Self::run_modifier(
123                    modifier.clone(),
124                    source_to_run.clone(),
125                    result_consumer,
126                    forked_mode,
127                ) {
128                    Ok(res) => next_sources.extend(res),
129                    Err(err) => return Err(err),
130                }
131            }
132            if next_sources.is_empty() {
133                return Ok(R::new(0));
134            }
135            current_sources = next_sources;
136        }
137
138        let mut summed = 0;
139        for execution_source in current_sources {
140            let res = self.run_executable(
141                self.executable.clone(),
142                execution_source,
143                result_consumer,
144                forked_mode,
145            )?;
146            match res.as_i32() {
147                Some(res) => summed += res,
148                None => return Ok(res),
149            }
150        }
151
152        Ok(R::new(summed))
153    }
154
155    pub fn stage(&self) -> Stage {
156        if self.modifiers.is_empty() {
157            Stage::Execute
158        } else {
159            Stage::Modify
160        }
161    }
162
163    pub fn top_context(&self) -> Rc<CommandContext<S, R>> {
164        self.modifiers
165            .first()
166            .cloned()
167            .unwrap_or_else(|| self.executable.clone())
168    }
169
170    pub fn next_stage(&mut self) -> Option<Rc<ContextChain<S, R>>> {
171        let modifier_count = self.modifiers.len();
172        if modifier_count == 0 {
173            return None;
174        }
175
176        if self.next_stage_cache.is_none() {
177            self.next_stage_cache = Some(Rc::new(ContextChain::new(
178                self.modifiers[1..].to_vec(),
179                self.executable.clone(),
180            )));
181        }
182
183        self.next_stage_cache.clone()
184    }
185}
186
187pub enum Stage {
188    Modify,
189    Execute,
190}