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 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}