azalea_brigadier/context/
context_chain.rs1use 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 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 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}