dsq_shared/ops/
logical_ops.rs

1//! Logical and conditional operations
2//!
3//! This module contains boolean logic and conditional execution operations.
4
5use crate::value::Value;
6use crate::Result;
7use std::any::Any;
8
9use super::traits::{Context, Operation};
10
11/// Logical AND operation
12///
13/// Performs logical AND on boolean values using truthiness rules.
14pub struct AndOperation {
15    /// Operations that produce the left operand
16    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
17    /// Operations that produce the right operand
18    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
19}
20
21impl AndOperation {
22    /// Creates a new logical AND operation with the given operand operations
23    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
91/// Logical OR operation
92///
93/// Performs logical OR on boolean values using truthiness rules.
94pub struct OrOperation {
95    /// Operations that produce the left operand
96    pub left_ops: Vec<Box<dyn Operation + Send + Sync>>,
97    /// Operations that produce the right operand
98    pub right_ops: Vec<Box<dyn Operation + Send + Sync>>,
99}
100
101impl OrOperation {
102    /// Creates a new logical OR operation with the given operand operations
103    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
171/// Conditional (if-then-else) operation
172///
173/// Evaluates a condition and returns the result of either the then or else branch.
174pub struct IfOperation {
175    /// Operations that produce the condition value
176    pub condition_ops: Vec<Box<dyn Operation + Send + Sync>>,
177    /// Operations to evaluate if condition is truthy
178    pub then_ops: Vec<Box<dyn Operation + Send + Sync>>,
179    /// Operations to evaluate if condition is falsy
180    pub else_ops: Vec<Box<dyn Operation + Send + Sync>>,
181}
182
183impl IfOperation {
184    /// Creates a new conditional operation with the given condition, then, and else operations
185    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
247/// Logical negation operation
248///
249/// Negates the truthiness of a value.
250pub struct NegationOperation {
251    /// Operations that produce the value to negate
252    pub expr_ops: Vec<Box<dyn Operation + Send + Sync>>,
253}
254
255impl NegationOperation {
256    /// Creates a new negation operation with the given expression operations
257    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}