1use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::{Context, Operation};
10
11pub struct AndOperation {
15 pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
17 pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
19}
20
21impl AndOperation {
22 pub fn new(
24 left_ops: Vec<Box<dyn Operation + Send + Sync>>,
25 right_ops: Vec<Box<dyn Operation + Send + Sync>>,
26 ) -> Self {
27 Self {
28 left_ops,
29 right_ops,
30 }
31 }
32}
33
34impl Operation for AndOperation {
35 fn apply(&self, value: &Value) -> Result<Value> {
36 let mut context = None;
37 self.apply_with_context(value, &mut context)
38 }
39
40 fn apply_with_context(
41 &self,
42 value: &Value,
43 context: &mut Option<&mut dyn Context>,
44 ) -> Result<Value> {
45 let mut left_val = value.clone();
46 for op in &self.left_ops {
47 left_val = op.apply_with_context(&left_val, context)?;
48 }
49
50 let left_truthy = match left_val {
51 Value::Bool(b) => b,
52 Value::Int(i) if i != 0 => true,
53 Value::Float(f) if f != 0.0 => true,
54 Value::String(s) if !s.is_empty() => true,
55 Value::Array(arr) if !arr.is_empty() => true,
56 Value::Object(obj) if !obj.is_empty() => true,
57 _ => false,
58 };
59
60 if !left_truthy {
61 return Ok(Value::Bool(false));
62 }
63
64 let mut right_val = value.clone();
65 for op in &self.right_ops {
66 right_val = op.apply_with_context(&right_val, context)?;
67 }
68
69 let right_truthy = match right_val {
70 Value::Bool(b) => b,
71 Value::Int(i) if i != 0 => true,
72 Value::Float(f) if f != 0.0 => true,
73 Value::String(s) if !s.is_empty() => true,
74 Value::Array(arr) if !arr.is_empty() => true,
75 Value::Object(obj) if !obj.is_empty() => true,
76 _ => false,
77 };
78
79 Ok(Value::Bool(right_truthy))
80 }
81
82 fn description(&self) -> String {
83 "logical and".to_string()
84 }
85
86 fn as_any(&self) -> &dyn Any {
87 self
88 }
89}
90
91pub struct OrOperation {
95 pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
97 pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
99}
100
101impl OrOperation {
102 pub fn new(
104 left_ops: Vec<Box<dyn Operation + Send + Sync>>,
105 right_ops: Vec<Box<dyn Operation + Send + Sync>>,
106 ) -> Self {
107 Self {
108 left_ops,
109 right_ops,
110 }
111 }
112}
113
114impl Operation for OrOperation {
115 fn apply(&self, value: &Value) -> Result<Value> {
116 let mut context = None;
117 self.apply_with_context(value, &mut context)
118 }
119
120 fn apply_with_context(
121 &self,
122 value: &Value,
123 context: &mut Option<&mut dyn Context>,
124 ) -> Result<Value> {
125 let mut left_val = value.clone();
126 for op in &self.left_ops {
127 left_val = op.apply_with_context(&left_val, context)?;
128 }
129
130 let left_truthy = match left_val {
131 Value::Bool(b) => b,
132 Value::Int(i) if i != 0 => true,
133 Value::Float(f) if f != 0.0 => true,
134 Value::String(s) if !s.is_empty() => true,
135 Value::Array(arr) if !arr.is_empty() => true,
136 Value::Object(obj) if !obj.is_empty() => true,
137 _ => false,
138 };
139
140 if left_truthy {
141 return Ok(Value::Bool(true));
142 }
143
144 let mut right_val = value.clone();
145 for op in &self.right_ops {
146 right_val = op.apply_with_context(&right_val, context)?;
147 }
148
149 let right_truthy = match right_val {
150 Value::Bool(b) => b,
151 Value::Int(i) if i != 0 => true,
152 Value::Float(f) if f != 0.0 => true,
153 Value::String(s) if !s.is_empty() => true,
154 Value::Array(arr) if !arr.is_empty() => true,
155 Value::Object(obj) if !obj.is_empty() => true,
156 _ => false,
157 };
158
159 Ok(Value::Bool(right_truthy))
160 }
161
162 fn description(&self) -> String {
163 "logical or".to_string()
164 }
165
166 fn as_any(&self) -> &dyn Any {
167 self
168 }
169}
170
171pub struct IfOperation {
175 pub condition_ops: Vec<Box<dyn Operation + Send + Sync>>,
177 pub then_ops: Vec<Box<dyn Operation + Send + Sync>>,
179 pub else_ops: Vec<Box<dyn Operation + Send + Sync>>,
181}
182
183impl IfOperation {
184 pub fn new(
186 condition_ops: Vec<Box<dyn Operation + Send + Sync>>,
187 then_ops: Vec<Box<dyn Operation + Send + Sync>>,
188 else_ops: Vec<Box<dyn Operation + Send + Sync>>,
189 ) -> Self {
190 Self {
191 condition_ops,
192 then_ops,
193 else_ops,
194 }
195 }
196}
197
198impl Operation for IfOperation {
199 fn apply(&self, value: &Value) -> Result<Value> {
200 self.apply_with_context(value, &mut None)
201 }
202
203 fn apply_with_context(
204 &self,
205 value: &Value,
206 context: &mut Option<&mut dyn Context>,
207 ) -> Result<Value> {
208 let mut condition_val = value.clone();
209 for op in &self.condition_ops {
210 condition_val = op.apply_with_context(&condition_val, context)?;
211 }
212
213 let condition_truthy = match condition_val {
214 Value::Bool(b) => b,
215 Value::Int(i) if i != 0 => true,
216 Value::Float(f) if f != 0.0 => true,
217 Value::String(s) if !s.is_empty() => true,
218 Value::Array(arr) if !arr.is_empty() => true,
219 Value::Object(obj) if !obj.is_empty() => true,
220 _ => false,
221 };
222
223 if condition_truthy {
224 let mut then_val = value.clone();
225 for op in &self.then_ops {
226 then_val = op.apply_with_context(&then_val, context)?;
227 }
228 Ok(then_val)
229 } else {
230 let mut else_val = value.clone();
231 for op in &self.else_ops {
232 else_val = op.apply_with_context(&else_val, context)?;
233 }
234 Ok(else_val)
235 }
236 }
237
238 fn description(&self) -> String {
239 "conditional".to_string()
240 }
241
242 fn as_any(&self) -> &dyn Any {
243 self
244 }
245}
246
247pub struct NegationOperation {
251 pub expr_ops: Vec<Box<dyn Operation + Send + Sync>>,
253}
254
255impl NegationOperation {
256 pub fn new(expr_ops: Vec<Box<dyn Operation + Send + Sync>>) -> Self {
258 Self { expr_ops }
259 }
260}
261
262impl Operation for NegationOperation {
263 fn apply(&self, value: &Value) -> Result<Value> {
264 let mut context = None;
265 self.apply_with_context(value, &mut context)
266 }
267
268 fn apply_with_context(
269 &self,
270 value: &Value,
271 context: &mut Option<&mut dyn Context>,
272 ) -> Result<Value> {
273 let mut expr_val = value.clone();
274 for op in &self.expr_ops {
275 expr_val = op.apply_with_context(&expr_val, context)?;
276 }
277
278 let truthy = match expr_val {
279 Value::Bool(b) => b,
280 Value::Int(i) if i != 0 => true,
281 Value::Float(f) if f != 0.0 => true,
282 Value::String(s) if !s.is_empty() => true,
283 Value::Array(arr) if !arr.is_empty() => true,
284 Value::Object(obj) if !obj.is_empty() => true,
285 _ => false,
286 };
287
288 Ok(Value::Bool(!truthy))
289 }
290
291 fn description(&self) -> String {
292 "logical not".to_string()
293 }
294
295 fn as_any(&self) -> &dyn Any {
296 self
297 }
298}