Skip to main content

dynamic/
ops.rs

1use super::Dynamic;
2
3use std::ops::{Neg, Not};
4impl Neg for Dynamic {
5    type Output = Self;
6    fn neg(self) -> Self::Output {
7        use Dynamic::*;
8        match self {
9            I8(i) => I8(i.wrapping_neg()),
10            I16(i) => I16(i.wrapping_neg()),
11            I32(i) => I32(i.wrapping_neg()),
12            I64(i) => I64(i.wrapping_neg()),
13            F32(f) => F32(-f),
14            F64(f) => F64(-f),
15            _ => Null,
16        }
17    }
18}
19
20impl Not for Dynamic {
21    type Output = Self;
22    fn not(self) -> Self::Output {
23        match self {
24            Self::Bool(b) => Self::Bool(!b),
25            Self::I8(i) => Self::I8(!i),
26            Self::I16(i) => Self::I16(!i),
27            Self::I32(i) => Self::I32(!i),
28            Self::I64(i) => Self::I64(!i),
29            Self::U8(i) => Self::U8(!i),
30            Self::U16(i) => Self::U16(!i),
31            Self::U32(i) => Self::U32(!i),
32            Self::U64(i) => Self::U64(!i),
33            _ => Self::Null,
34        }
35    }
36}
37
38use std::ops::{Add, Div, Mul, Rem, Sub};
39
40impl Add for Dynamic {
41    type Output = Self;
42    fn add(self, rhs: Self) -> Self::Output {
43        if self.is_list() {
44            self.clone().append(rhs);
45            return self;
46        } else if rhs.is_list() {
47            rhs.clone().append(self);
48            return rhs;
49        }
50        match (self, rhs) {
51            (Self::StringBuf(mut left), Self::StringBuf(right)) => {
52                left.push_str(&right);
53                return Self::StringBuf(left);
54            }
55            (Self::StringBuf(mut left), Self::String(right)) => {
56                left.push_str(right.as_str());
57                return Self::StringBuf(left);
58            }
59            (Self::StringBuf(mut left), right) => {
60                left.push_str(&right.to_string());
61                return Self::StringBuf(left);
62            }
63            (Self::String(left), Self::StringBuf(right)) => {
64                let mut out = String::with_capacity(left.len() + right.len());
65                out.push_str(left.as_str());
66                out.push_str(&right);
67                return Self::StringBuf(out);
68            }
69            (Self::String(left), Self::String(right)) => {
70                let mut out = String::with_capacity(left.len() + right.len());
71                out.push_str(left.as_str());
72                out.push_str(right.as_str());
73                return Self::StringBuf(out);
74            }
75            (Self::String(left), right) => {
76                let right = right.to_string();
77                let mut out = String::with_capacity(left.len() + right.len());
78                out.push_str(left.as_str());
79                out.push_str(&right);
80                return Self::StringBuf(out);
81            }
82            (left, Self::StringBuf(right)) => {
83                let left = left.to_string();
84                let mut out = String::with_capacity(left.len() + right.len());
85                out.push_str(&left);
86                out.push_str(&right);
87                return Self::StringBuf(out);
88            }
89            (left, Self::String(right)) => {
90                let left = left.to_string();
91                let mut out = String::with_capacity(left.len() + right.len());
92                out.push_str(&left);
93                out.push_str(right.as_str());
94                return Self::StringBuf(out);
95            }
96            (left, right) => {
97                if left.is_f64() || right.is_f64() {
98                    return Dynamic::F64(left.as_float().unwrap_or(0.0) + right.as_float().unwrap_or(0.0));
99                } else if left.is_f32() || right.is_f32() {
100                    return Dynamic::F32(left.as_float().unwrap_or(0.0) as f32 + right.as_float().unwrap_or(0.0) as f32);
101                }
102                if left.is_int() || right.is_int() {
103                    return Self::I64(left.as_int().unwrap() + right.as_int().unwrap());
104                }
105                if left.is_uint() || right.is_uint() {
106                    return Self::U64(left.as_uint().unwrap() + right.as_uint().unwrap());
107                }
108                if left.is_map() && right.is_map() {
109                    left.append(right);
110                }
111                left
112            }
113        }
114    }
115}
116
117impl Mul for Dynamic {
118    type Output = Self;
119    fn mul(self, rhs: Self) -> Self::Output {
120        if self.is_f64() || rhs.is_f64() {
121            return Dynamic::F64(self.as_float().unwrap_or(0.0) * rhs.as_float().unwrap_or(0.0));
122        } else if self.is_f32() || rhs.is_f32() {
123            return Dynamic::F32(self.as_float().unwrap_or(0.0) as f32 * rhs.as_float().unwrap_or(0.0) as f32);
124        }
125        if self.is_int() || rhs.is_int() {
126            return Self::I64(self.as_int().unwrap_or(0) * rhs.as_int().unwrap_or(0));
127        }
128        if self.is_uint() || rhs.is_uint() {
129            return Self::U64(self.as_uint().unwrap_or(0) * rhs.as_uint().unwrap_or(0));
130        }
131        self
132    }
133}
134
135impl Sub for Dynamic {
136    type Output = Self;
137    fn sub(self, rhs: Self) -> Self::Output {
138        if self.is_f64() || rhs.is_f64() {
139            return Dynamic::F64(self.as_float().unwrap() - rhs.as_float().unwrap());
140        } else if self.is_f32() || rhs.is_f32() {
141            return Dynamic::F32(self.as_float().unwrap() as f32 - rhs.as_float().unwrap() as f32);
142        }
143        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
144            return Self::I64(self.as_int().unwrap() - rhs.as_int().unwrap());
145        }
146        if self.is_list() && rhs.is_list() {
147            if self.len() == rhs.len() {}
148        }
149        self
150    }
151}
152
153impl Div for Dynamic {
154    type Output = Self;
155    fn div(self, rhs: Self) -> Self::Output {
156        if self.is_f64() || rhs.is_f64() {
157            return Dynamic::F64(self.as_float().unwrap() / rhs.as_float().unwrap());
158        } else if self.is_f32() || rhs.is_f32() {
159            return Dynamic::F32(self.as_float().unwrap() as f32 / rhs.as_float().unwrap() as f32);
160        }
161        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
162            return Self::I64(self.as_int().unwrap() / rhs.as_int().unwrap());
163        }
164        self
165    }
166}
167
168impl Rem for Dynamic {
169    type Output = Self;
170    fn rem(self, rhs: Self) -> Self::Output {
171        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
172            return Self::I64(self.as_int().unwrap() % rhs.as_int().unwrap());
173        }
174        self
175    }
176}
177
178use std::ops::{Shl, Shr};
179
180impl Shl for Dynamic {
181    type Output = Self;
182    fn shl(self, rhs: Self) -> Self::Output {
183        use Dynamic::*;
184        let shift = u64::try_from(rhs).unwrap();
185        match self {
186            I8(i) => I8(i << shift),
187            I16(i) => I16(i << shift),
188            I32(i) => I32(i << shift),
189            I64(i) => I64(i << shift),
190            U8(i) => U8(i << shift),
191            U16(i) => U16(i << shift),
192            U32(i) => U32(i << shift),
193            U64(i) => U64(i << shift),
194            _ => panic!("Cannot shift non-integer types"),
195        }
196    }
197}
198
199impl Shr for Dynamic {
200    type Output = Self;
201    fn shr(self, rhs: Self) -> Self::Output {
202        use Dynamic::*;
203        let shift = u64::try_from(rhs).unwrap();
204        match self {
205            I8(i) => I8(i >> shift),
206            I16(i) => I16(i >> shift),
207            I32(i) => I32(i >> shift),
208            I64(i) => I64(i >> shift),
209            U8(i) => U8(i >> shift),
210            U16(i) => U16(i >> shift),
211            U32(i) => U32(i >> shift),
212            U64(i) => U64(i >> shift),
213            _ => panic!("Cannot shift non-integer types"),
214        }
215    }
216}
217
218use std::ops::{BitAnd, BitOr, BitXor};
219impl BitAnd for Dynamic {
220    type Output = Self;
221    fn bitand(self, rhs: Self) -> Self::Output {
222        let ty = self.get_type() + rhs.get_type();
223        let left = ty.force(self).unwrap();
224        let right = ty.force(rhs).unwrap();
225        match (left, right) {
226            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l & r),
227            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l & r),
228            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l & r),
229            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l & r),
230            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l & r),
231            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l & r),
232            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l & r),
233            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l & r),
234            (_, _) => Dynamic::Null,
235        }
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use super::*;
242
243    #[test]
244    fn negating_signed_min_values_does_not_panic() {
245        assert_eq!(-Dynamic::I8(i8::MIN), Dynamic::I8(i8::MIN));
246        assert_eq!(-Dynamic::I16(i16::MIN), Dynamic::I16(i16::MIN));
247        assert_eq!(-Dynamic::I32(i32::MIN), Dynamic::I32(i32::MIN));
248        assert_eq!(-Dynamic::I64(i64::MIN), Dynamic::I64(i64::MIN));
249    }
250
251    #[test]
252    fn not_is_logical_for_bool_and_bitwise_for_ints() {
253        assert_eq!(!Dynamic::Bool(false), Dynamic::Bool(true));
254        assert_eq!(!Dynamic::I32(0b1010), Dynamic::I32(!0b1010));
255        assert_eq!(!Dynamic::U32(0b1010), Dynamic::U32(!0b1010));
256    }
257}
258
259impl BitOr for Dynamic {
260    type Output = Self;
261    fn bitor(self, rhs: Self) -> Self::Output {
262        let ty = self.get_type() + rhs.get_type();
263        let left = ty.force(self).unwrap();
264        let right = ty.force(rhs).unwrap();
265        match (left, right) {
266            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l | r),
267            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l | r),
268            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l | r),
269            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l | r),
270            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l | r),
271            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l | r),
272            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l | r),
273            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l | r),
274            (_, _) => Dynamic::Null,
275        }
276    }
277}
278
279impl BitXor for Dynamic {
280    type Output = Self;
281    fn bitxor(self, rhs: Self) -> Self::Output {
282        let ty = self.get_type() + rhs.get_type();
283        let left = ty.force(self).unwrap();
284        let right = ty.force(rhs).unwrap();
285        match (left, right) {
286            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l ^ r),
287            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l ^ r),
288            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l ^ r),
289            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l ^ r),
290            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l ^ r),
291            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l ^ r),
292            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l ^ r),
293            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l ^ r),
294            (_, _) => Dynamic::Null,
295        }
296    }
297}