gitql_core/values/
integer.rs

1use std::any::Any;
2use std::cmp::Ordering;
3
4use gitql_ast::operator::GroupComparisonOperator;
5use gitql_ast::types::integer::IntType;
6use gitql_ast::types::DataType;
7
8use super::base::Value;
9use super::boolean::BoolValue;
10use super::float::FloatValue;
11
12#[derive(Clone)]
13pub struct IntValue {
14    pub value: i64,
15}
16
17impl IntValue {
18    pub fn new(value: i64) -> Self {
19        IntValue { value }
20    }
21
22    pub fn new_zero() -> Self {
23        IntValue { value: 0 }
24    }
25}
26
27impl Value for IntValue {
28    fn literal(&self) -> String {
29        self.value.to_string()
30    }
31
32    fn equals(&self, other: &Box<dyn Value>) -> bool {
33        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
34            return self.value == other_int.value;
35        }
36        false
37    }
38
39    fn compare(&self, other: &Box<dyn Value>) -> Option<Ordering> {
40        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
41            return self.value.partial_cmp(&other_int.value);
42        }
43        None
44    }
45
46    fn data_type(&self) -> Box<dyn DataType> {
47        Box::new(IntType)
48    }
49
50    fn as_any(&self) -> &dyn Any {
51        self
52    }
53
54    fn add_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
55        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
56            let value = self.value + other_int.value;
57            return Ok(Box::new(IntValue::new(value)));
58        }
59        Err("Unexpected type to perform `+` with".to_string())
60    }
61
62    fn sub_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
63        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
64            let value = self.value - other_int.value;
65            return Ok(Box::new(IntValue::new(value)));
66        }
67        Err("Unexpected type to perform `-` with".to_string())
68    }
69
70    fn mul_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
71        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
72            let value = self.value * other_int.value;
73            return Ok(Box::new(IntValue::new(value)));
74        }
75        Err("Unexpected type to perform `*` with".to_string())
76    }
77
78    fn div_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
79        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
80            if other_int.value == 0 {
81                return Err("Can't perform `/` operator with 0 value".to_string());
82            }
83            let value = self.value / other_int.value;
84            return Ok(Box::new(IntValue::new(value)));
85        }
86        Err("Unexpected type to perform `/` with".to_string())
87    }
88
89    fn rem_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
90        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
91            let value = self.value % other_int.value;
92            return Ok(Box::new(IntValue::new(value)));
93        }
94        Err("Unexpected type to perform `%` with".to_string())
95    }
96
97    fn caret_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
98        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
99            if other_int.value < 0 {
100                return Err("Caret right side hand can't be negative value".to_string());
101            }
102            let value = self.value.pow(other_int.value as u32);
103            return Ok(Box::new(IntValue::new(value)));
104        }
105        Err("Unexpected type to perform `^` with".to_string())
106    }
107
108    fn or_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
109        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
110            let value = self.value | other_int.value;
111            return Ok(Box::new(IntValue::new(value)));
112        }
113        Err("Unexpected type to perform `|` with".to_string())
114    }
115
116    fn and_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
117        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
118            let value = self.value & other_int.value;
119            return Ok(Box::new(IntValue::new(value)));
120        }
121        Err("Unexpected type to perform `&` with".to_string())
122    }
123
124    fn xor_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
125        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
126            let value = self.value ^ other_int.value;
127            return Ok(Box::new(IntValue::new(value)));
128        }
129        Err("Unexpected type to perform `^` with".to_string())
130    }
131
132    fn shl_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
133        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
134            let value = self.value << other_int.value;
135            return Ok(Box::new(IntValue::new(value)));
136        }
137        Err("Unexpected type to perform `<<` with".to_string())
138    }
139
140    fn shr_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
141        if let Some(other_int) = other.as_any().downcast_ref::<IntValue>() {
142            let value = self.value >> other_int.value;
143            return Ok(Box::new(IntValue::new(value)));
144        }
145        Err("Unexpected type to perform `>>` with".to_string())
146    }
147
148    fn eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
149        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
150            let value = self.value == other_bool.value;
151            return Ok(Box::new(BoolValue::new(value)));
152        }
153        Err("Unexpected type to perform `=` with".to_string())
154    }
155
156    fn group_eq_op(
157        &self,
158        other: &Box<dyn Value>,
159        group_op: &GroupComparisonOperator,
160    ) -> Result<Box<dyn Value>, String> {
161        if other.is_array_of(|element_type| element_type.is_int()) {
162            let elements = &other.as_array().unwrap();
163            let mut matches_count = 0;
164            for element in elements.iter() {
165                if self.value == element.as_int().unwrap() {
166                    matches_count += 1;
167                    if GroupComparisonOperator::Any.eq(group_op) {
168                        break;
169                    }
170                }
171            }
172
173            let result = match group_op {
174                GroupComparisonOperator::All => matches_count == elements.len(),
175                GroupComparisonOperator::Any => matches_count > 0,
176            };
177
178            return Ok(Box::new(BoolValue::new(result)));
179        }
180        Err("Unexpected type to perform `=` with".to_string())
181    }
182
183    fn bang_eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
184        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
185            let value = self.value != other_bool.value;
186            return Ok(Box::new(BoolValue::new(value)));
187        }
188        Err("Unexpected type to perform `!=` with".to_string())
189    }
190
191    fn group_bang_eq_op(
192        &self,
193        other: &Box<dyn Value>,
194        group_op: &GroupComparisonOperator,
195    ) -> Result<Box<dyn Value>, String> {
196        if other.is_array_of(|element_type| element_type.is_int()) {
197            let elements = &other.as_array().unwrap();
198            let mut matches_count = 0;
199            for element in elements.iter() {
200                if self.value != element.as_int().unwrap() {
201                    matches_count += 1;
202                    if GroupComparisonOperator::Any.eq(group_op) {
203                        break;
204                    }
205                }
206            }
207
208            let result = match group_op {
209                GroupComparisonOperator::All => matches_count == elements.len(),
210                GroupComparisonOperator::Any => matches_count > 0,
211            };
212
213            return Ok(Box::new(BoolValue::new(result)));
214        }
215        Err("Unexpected type to perform `!=` with".to_string())
216    }
217
218    fn gt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
219        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
220            let value = self.value > other_bool.value;
221            return Ok(Box::new(BoolValue::new(value)));
222        }
223        Err("Unexpected type to perform `>` with".to_string())
224    }
225
226    fn group_gt_op(
227        &self,
228        other: &Box<dyn Value>,
229        group_op: &GroupComparisonOperator,
230    ) -> Result<Box<dyn Value>, String> {
231        if other.is_array_of(|element_type| element_type.is_int()) {
232            let elements = &other.as_array().unwrap();
233            let mut matches_count = 0;
234            for element in elements.iter() {
235                if self.value > element.as_int().unwrap() {
236                    matches_count += 1;
237                    if GroupComparisonOperator::Any.eq(group_op) {
238                        break;
239                    }
240                }
241            }
242
243            let result = match group_op {
244                GroupComparisonOperator::All => matches_count == elements.len(),
245                GroupComparisonOperator::Any => matches_count > 0,
246            };
247
248            return Ok(Box::new(BoolValue::new(result)));
249        }
250        Err("Unexpected type to perform `>` with".to_string())
251    }
252
253    fn gte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
254        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
255            let value = self.value >= other_bool.value;
256            return Ok(Box::new(BoolValue::new(value)));
257        }
258        Err("Unexpected type to perform `>` with".to_string())
259    }
260
261    fn group_gte_op(
262        &self,
263        other: &Box<dyn Value>,
264        group_op: &GroupComparisonOperator,
265    ) -> Result<Box<dyn Value>, String> {
266        if other.is_array_of(|element_type| element_type.is_int()) {
267            let elements = &other.as_array().unwrap();
268            let mut matches_count = 0;
269            for element in elements.iter() {
270                if self.value >= element.as_int().unwrap() {
271                    matches_count += 1;
272                    if GroupComparisonOperator::Any.eq(group_op) {
273                        break;
274                    }
275                }
276            }
277
278            let result = match group_op {
279                GroupComparisonOperator::All => matches_count == elements.len(),
280                GroupComparisonOperator::Any => matches_count > 0,
281            };
282
283            return Ok(Box::new(BoolValue::new(result)));
284        }
285        Err("Unexpected type to perform `>=` with".to_string())
286    }
287
288    fn lt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
289        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
290            let value = self.value < other_bool.value;
291            return Ok(Box::new(BoolValue::new(value)));
292        }
293        Err("Unexpected type to perform `<` with".to_string())
294    }
295
296    fn group_lt_op(
297        &self,
298        other: &Box<dyn Value>,
299        group_op: &GroupComparisonOperator,
300    ) -> Result<Box<dyn Value>, String> {
301        if other.is_array_of(|element_type| element_type.is_int()) {
302            let elements = &other.as_array().unwrap();
303            let mut matches_count = 0;
304            for element in elements.iter() {
305                if self.value < element.as_int().unwrap() {
306                    matches_count += 1;
307                    if GroupComparisonOperator::Any.eq(group_op) {
308                        break;
309                    }
310                }
311            }
312
313            let result = match group_op {
314                GroupComparisonOperator::All => matches_count == elements.len(),
315                GroupComparisonOperator::Any => matches_count > 0,
316            };
317
318            return Ok(Box::new(BoolValue::new(result)));
319        }
320        Err("Unexpected type to perform `<` with".to_string())
321    }
322
323    fn lte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
324        if let Some(other_bool) = other.as_any().downcast_ref::<IntValue>() {
325            let value = self.value <= other_bool.value;
326            return Ok(Box::new(BoolValue::new(value)));
327        }
328        Err("Unexpected type to perform `<=` with".to_string())
329    }
330
331    fn group_lte_op(
332        &self,
333        other: &Box<dyn Value>,
334        group_op: &GroupComparisonOperator,
335    ) -> Result<Box<dyn Value>, String> {
336        if other.is_array_of(|element_type| element_type.is_int()) {
337            let elements = &other.as_array().unwrap();
338            let mut matches_count = 0;
339            for element in elements.iter() {
340                if self.value <= element.as_int().unwrap() {
341                    matches_count += 1;
342                    if GroupComparisonOperator::Any.eq(group_op) {
343                        break;
344                    }
345                }
346            }
347
348            let result = match group_op {
349                GroupComparisonOperator::All => matches_count == elements.len(),
350                GroupComparisonOperator::Any => matches_count > 0,
351            };
352
353            return Ok(Box::new(BoolValue::new(result)));
354        }
355        Err("Unexpected type to perform `<=` with".to_string())
356    }
357
358    fn neg_op(&self) -> Result<Box<dyn Value>, String> {
359        Ok(Box::new(IntValue { value: -self.value }))
360    }
361
362    fn cast_op(&self, target_type: &Box<dyn DataType>) -> Result<Box<dyn Value>, String> {
363        // Cast to Boolean
364        if target_type.is_bool() {
365            let value = self.value != 0;
366            return Ok(Box::new(BoolValue::new(value)));
367        }
368
369        // Cast to Float
370        if target_type.is_float() {
371            let value = self.value as f64;
372            return Ok(Box::new(FloatValue { value }));
373        }
374
375        Err("Unexpected value to perform `CAST` with".to_string())
376    }
377}