partiql_value/value/
math.rs

1use crate::util;
2use crate::Value;
3use std::ops;
4
5impl ops::Add for &Value {
6    type Output = Value;
7
8    fn add(self, rhs: Self) -> Self::Output {
9        match (&self, &rhs) {
10            // TODO: edge cases dealing with overflow
11            (Value::Missing, _) => Value::Missing,
12            (_, Value::Missing) => Value::Missing,
13            (Value::Null, _) => Value::Null,
14            (_, Value::Null) => Value::Null,
15            (Value::Integer(l), Value::Integer(r)) => Value::Integer(l + r),
16            (Value::Real(l), Value::Real(r)) => Value::Real(*l + *r),
17            (Value::Decimal(l), Value::Decimal(r)) => {
18                Value::Decimal(Box::new(l.as_ref() + r.as_ref()))
19            }
20            (Value::Integer(_), Value::Real(_)) => &util::coerce_int_to_real(self) + rhs,
21            (Value::Integer(_), Value::Decimal(_)) => {
22                &util::coerce_int_or_real_to_decimal(self) + rhs
23            }
24            (Value::Real(_), Value::Decimal(_)) => &util::coerce_int_or_real_to_decimal(self) + rhs,
25            (Value::Real(_), Value::Integer(_)) => self + &util::coerce_int_to_real(rhs),
26            (Value::Decimal(_), Value::Integer(_)) => {
27                self + &util::coerce_int_or_real_to_decimal(rhs)
28            }
29            (Value::Decimal(_), Value::Real(_)) => self + &util::coerce_int_or_real_to_decimal(rhs),
30            _ => Value::Missing, // data type mismatch => Missing
31        }
32    }
33}
34
35impl ops::AddAssign<&Value> for Value {
36    fn add_assign(&mut self, rhs: &Value) {
37        match (self, &rhs) {
38            // TODO: edge cases dealing with overflow
39            (Value::Missing, _) => {}
40            (this, Value::Missing) => *this = Value::Missing,
41            (Value::Null, _) => {}
42            (this, Value::Null) => *this = Value::Null,
43
44            (Value::Integer(l), Value::Integer(r)) => l.add_assign(r),
45
46            (Value::Real(l), Value::Real(r)) => l.add_assign(r),
47            (Value::Real(l), Value::Integer(i)) => l.add_assign(*i as f64),
48
49            (Value::Decimal(l), Value::Decimal(r)) => l.add_assign(r.as_ref()),
50            (Value::Decimal(l), Value::Integer(i)) => l.add_assign(rust_decimal::Decimal::from(*i)),
51            (Value::Decimal(l), Value::Real(r)) => match util::coerce_f64_to_decimal(r) {
52                Some(d) => l.add_assign(d),
53                None => todo!(),
54            },
55
56            (this, Value::Real(r)) => {
57                *this = match &this {
58                    Value::Integer(l) => Value::from((*l as f64) + r.0),
59                    _ => Value::Missing,
60                };
61            }
62            (this, Value::Decimal(r)) => {
63                *this = match &this {
64                    Value::Integer(l) => {
65                        Value::Decimal(Box::new(rust_decimal::Decimal::from(*l) + r.as_ref()))
66                    }
67                    Value::Real(l) => match util::coerce_f64_to_decimal(&l.0) {
68                        None => Value::Missing,
69                        Some(d) => Value::Decimal(Box::new(d + r.as_ref())),
70                    },
71                    _ => Value::Missing,
72                };
73            }
74            (this, _) => *this = Value::Missing, // data type mismatch => Missing
75        }
76    }
77}
78
79pub trait UnaryPlus {
80    type Output;
81
82    fn positive(self) -> Self::Output;
83}
84
85impl UnaryPlus for Value {
86    type Output = Self;
87    fn positive(self) -> Self::Output {
88        match self {
89            Value::Null => Value::Null,
90            Value::Missing => Value::Missing,
91            Value::Integer(_) | Value::Real(_) | Value::Decimal(_) => self,
92            _ => Value::Missing, // data type mismatch => Missing
93        }
94    }
95}
96
97impl ops::Sub for &Value {
98    type Output = Value;
99
100    fn sub(self, rhs: Self) -> Self::Output {
101        match (&self, &rhs) {
102            // TODO: edge cases dealing with overflow
103            (Value::Missing, _) => Value::Missing,
104            (_, Value::Missing) => Value::Missing,
105            (Value::Null, _) => Value::Null,
106            (_, Value::Null) => Value::Null,
107            (Value::Integer(l), Value::Integer(r)) => Value::Integer(l - r),
108            (Value::Real(l), Value::Real(r)) => Value::Real(*l - *r),
109            (Value::Decimal(l), Value::Decimal(r)) => {
110                Value::Decimal(Box::new(l.as_ref() - r.as_ref()))
111            }
112            (Value::Integer(_), Value::Real(_)) => &util::coerce_int_to_real(self) - rhs,
113            (Value::Integer(_), Value::Decimal(_)) => {
114                &util::coerce_int_or_real_to_decimal(self) - rhs
115            }
116            (Value::Real(_), Value::Decimal(_)) => &util::coerce_int_or_real_to_decimal(self) - rhs,
117            (Value::Real(_), Value::Integer(_)) => self - &util::coerce_int_to_real(rhs),
118            (Value::Decimal(_), Value::Integer(_)) => {
119                self - &util::coerce_int_or_real_to_decimal(rhs)
120            }
121            (Value::Decimal(_), Value::Real(_)) => self - &util::coerce_int_or_real_to_decimal(rhs),
122            _ => Value::Missing, // data type mismatch => Missing
123        }
124    }
125}
126
127impl ops::Mul for &Value {
128    type Output = Value;
129
130    fn mul(self, rhs: Self) -> Self::Output {
131        match (&self, &rhs) {
132            // TODO: edge cases dealing with overflow
133            (Value::Missing, _) => Value::Missing,
134            (_, Value::Missing) => Value::Missing,
135            (Value::Null, _) => Value::Null,
136            (_, Value::Null) => Value::Null,
137            (Value::Integer(l), Value::Integer(r)) => Value::Integer(l * r),
138            (Value::Real(l), Value::Real(r)) => Value::Real(*l * *r),
139            (Value::Decimal(l), Value::Decimal(r)) => {
140                Value::Decimal(Box::new(l.as_ref() * r.as_ref()))
141            }
142            (Value::Integer(_), Value::Real(_)) => &util::coerce_int_to_real(self) * rhs,
143            (Value::Integer(_), Value::Decimal(_)) => {
144                &util::coerce_int_or_real_to_decimal(self) * rhs
145            }
146            (Value::Real(_), Value::Decimal(_)) => &util::coerce_int_or_real_to_decimal(self) * rhs,
147            (Value::Real(_), Value::Integer(_)) => self * &util::coerce_int_to_real(rhs),
148            (Value::Decimal(_), Value::Integer(_)) => {
149                self * &util::coerce_int_or_real_to_decimal(rhs)
150            }
151            (Value::Decimal(_), Value::Real(_)) => self * &util::coerce_int_or_real_to_decimal(rhs),
152            _ => Value::Missing, // data type mismatch => Missing
153        }
154    }
155}
156
157impl ops::Div for &Value {
158    type Output = Value;
159
160    fn div(self, rhs: Self) -> Self::Output {
161        match (&self, &rhs) {
162            // TODO: edge cases dealing with division by 0
163            (Value::Missing, _) => Value::Missing,
164            (_, Value::Missing) => Value::Missing,
165            (Value::Null, _) => Value::Null,
166            (_, Value::Null) => Value::Null,
167            (Value::Integer(l), Value::Integer(r)) => Value::Integer(l / r),
168            (Value::Real(l), Value::Real(r)) => Value::Real(*l / *r),
169            (Value::Decimal(l), Value::Decimal(r)) => {
170                Value::Decimal(Box::new(l.as_ref() / r.as_ref()))
171            }
172            (Value::Integer(_), Value::Real(_)) => &util::coerce_int_to_real(self) / rhs,
173            (Value::Integer(_), Value::Decimal(_)) => {
174                &util::coerce_int_or_real_to_decimal(self) / rhs
175            }
176            (Value::Real(_), Value::Decimal(_)) => &util::coerce_int_or_real_to_decimal(self) / rhs,
177            (Value::Real(_), Value::Integer(_)) => self / &util::coerce_int_to_real(rhs),
178            (Value::Decimal(_), Value::Integer(_)) => {
179                self / &util::coerce_int_or_real_to_decimal(rhs)
180            }
181            (Value::Decimal(_), Value::Real(_)) => self / &util::coerce_int_or_real_to_decimal(rhs),
182            _ => Value::Missing, // data type mismatch => Missing
183        }
184    }
185}
186
187impl ops::Rem for &Value {
188    type Output = Value;
189
190    fn rem(self, rhs: Self) -> Self::Output {
191        match (&self, &rhs) {
192            // TODO: edge cases dealing with division by 0
193            (Value::Missing, _) => Value::Missing,
194            (_, Value::Missing) => Value::Missing,
195            (Value::Null, _) => Value::Null,
196            (_, Value::Null) => Value::Null,
197            (Value::Integer(l), Value::Integer(r)) => Value::Integer(l % r),
198            (Value::Real(l), Value::Real(r)) => Value::Real(*l % *r),
199            (Value::Decimal(l), Value::Decimal(r)) => {
200                Value::Decimal(Box::new(l.as_ref() % r.as_ref()))
201            }
202            (Value::Integer(_), Value::Real(_)) => &util::coerce_int_to_real(self) % rhs,
203            (Value::Integer(_), Value::Decimal(_)) => {
204                &util::coerce_int_or_real_to_decimal(self) % rhs
205            }
206            (Value::Real(_), Value::Decimal(_)) => &util::coerce_int_or_real_to_decimal(self) % rhs,
207            (Value::Real(_), Value::Integer(_)) => self % &util::coerce_int_to_real(rhs),
208            (Value::Decimal(_), Value::Integer(_)) => {
209                self % &util::coerce_int_or_real_to_decimal(rhs)
210            }
211            (Value::Decimal(_), Value::Real(_)) => self % &util::coerce_int_or_real_to_decimal(rhs),
212            _ => Value::Missing, // data type mismatch => Missing
213        }
214    }
215}
216
217impl ops::Neg for &Value {
218    type Output = Value;
219
220    fn neg(self) -> Self::Output {
221        match self {
222            // TODO: handle overflow for negation
223            Value::Null => Value::Null,
224            Value::Missing => Value::Missing,
225            Value::Integer(i) => Value::from(-i),
226            Value::Real(f) => Value::Real(-f),
227            Value::Decimal(d) => Value::from(-d.as_ref()),
228            _ => Value::Missing, // data type mismatch => Missing
229        }
230    }
231}
232
233impl ops::Neg for Value {
234    type Output = Value;
235
236    fn neg(self) -> Self::Output {
237        match self {
238            // TODO: handle overflow for negation
239            Value::Null => self,
240            Value::Missing => self,
241            Value::Integer(i) => Value::from(-i),
242            Value::Real(f) => Value::Real(-f),
243            Value::Decimal(d) => Value::from(-d.as_ref()),
244            _ => Value::Missing, // data type mismatch => Missing
245        }
246    }
247}