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        if let (Self::String(left), Self::String(right)) = (&self, &rhs) {
51            let mut out = String::with_capacity(left.len() + right.len());
52            out.push_str(left.as_str());
53            out.push_str(right.as_str());
54            return Self::String(out.into());
55        } else if let Self::String(left) = &self {
56            let right = rhs.to_string();
57            let mut out = String::with_capacity(left.len() + right.len());
58            out.push_str(left.as_str());
59            out.push_str(&right);
60            return Self::String(out.into());
61        } else if let Self::String(right) = &rhs {
62            let left = self.to_string();
63            let mut out = String::with_capacity(left.len() + right.len());
64            out.push_str(&left);
65            out.push_str(right.as_str());
66            return Self::String(out.into());
67        } else if self.is_f64() || rhs.is_f64() {
68            return Dynamic::F64(self.as_float().unwrap_or(0.0) + rhs.as_float().unwrap_or(0.0));
69        } else if self.is_f32() || rhs.is_f32() {
70            return Dynamic::F32(self.as_float().unwrap_or(0.0) as f32 + rhs.as_float().unwrap_or(0.0) as f32);
71        }
72        if self.is_int() || rhs.is_int() {
73            return Self::I64(self.as_int().unwrap() + rhs.as_int().unwrap());
74        }
75        if self.is_uint() || rhs.is_uint() {
76            return Self::U64(self.as_uint().unwrap() + rhs.as_uint().unwrap());
77        }
78        if self.is_map() && rhs.is_map() {
79            self.append(rhs);
80        }
81        self
82    }
83}
84
85impl Mul for Dynamic {
86    type Output = Self;
87    fn mul(self, rhs: Self) -> Self::Output {
88        if self.is_f64() || rhs.is_f64() {
89            return Dynamic::F64(self.as_float().unwrap_or(0.0) * rhs.as_float().unwrap_or(0.0));
90        } else if self.is_f32() || rhs.is_f32() {
91            return Dynamic::F32(self.as_float().unwrap_or(0.0) as f32 * rhs.as_float().unwrap_or(0.0) as f32);
92        }
93        if self.is_int() || rhs.is_int() {
94            return Self::I64(self.as_int().unwrap_or(0) * rhs.as_int().unwrap_or(0));
95        }
96        if self.is_uint() || rhs.is_uint() {
97            return Self::U64(self.as_uint().unwrap_or(0) * rhs.as_uint().unwrap_or(0));
98        }
99        self
100    }
101}
102
103impl Sub for Dynamic {
104    type Output = Self;
105    fn sub(self, rhs: Self) -> Self::Output {
106        if self.is_f64() || rhs.is_f64() {
107            return Dynamic::F64(self.as_float().unwrap() - rhs.as_float().unwrap());
108        } else if self.is_f32() || rhs.is_f32() {
109            return Dynamic::F32(self.as_float().unwrap() as f32 - rhs.as_float().unwrap() as f32);
110        }
111        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
112            return Self::I64(self.as_int().unwrap() - rhs.as_int().unwrap());
113        }
114        if self.is_list() && rhs.is_list() {
115            if self.len() == rhs.len() {}
116        }
117        self
118    }
119}
120
121impl Div for Dynamic {
122    type Output = Self;
123    fn div(self, rhs: Self) -> Self::Output {
124        if self.is_f64() || rhs.is_f64() {
125            return Dynamic::F64(self.as_float().unwrap() / rhs.as_float().unwrap());
126        } else if self.is_f32() || rhs.is_f32() {
127            return Dynamic::F32(self.as_float().unwrap() as f32 / rhs.as_float().unwrap() as f32);
128        }
129        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
130            return Self::I64(self.as_int().unwrap() / rhs.as_int().unwrap());
131        }
132        self
133    }
134}
135
136impl Rem for Dynamic {
137    type Output = Self;
138    fn rem(self, rhs: Self) -> Self::Output {
139        if self.is_int() || rhs.is_int() || self.is_uint() || rhs.is_uint() {
140            return Self::I64(self.as_int().unwrap() % rhs.as_int().unwrap());
141        }
142        self
143    }
144}
145
146use std::ops::{Shl, Shr};
147
148impl Shl for Dynamic {
149    type Output = Self;
150    fn shl(self, rhs: Self) -> Self::Output {
151        use Dynamic::*;
152        let shift = u64::try_from(rhs).unwrap();
153        match self {
154            I8(i) => I8(i << shift),
155            I16(i) => I16(i << shift),
156            I32(i) => I32(i << shift),
157            I64(i) => I64(i << shift),
158            U8(i) => U8(i << shift),
159            U16(i) => U16(i << shift),
160            U32(i) => U32(i << shift),
161            U64(i) => U64(i << shift),
162            _ => panic!("Cannot shift non-integer types"),
163        }
164    }
165}
166
167impl Shr for Dynamic {
168    type Output = Self;
169    fn shr(self, rhs: Self) -> Self::Output {
170        use Dynamic::*;
171        let shift = u64::try_from(rhs).unwrap();
172        match self {
173            I8(i) => I8(i >> shift),
174            I16(i) => I16(i >> shift),
175            I32(i) => I32(i >> shift),
176            I64(i) => I64(i >> shift),
177            U8(i) => U8(i >> shift),
178            U16(i) => U16(i >> shift),
179            U32(i) => U32(i >> shift),
180            U64(i) => U64(i >> shift),
181            _ => panic!("Cannot shift non-integer types"),
182        }
183    }
184}
185
186use std::ops::{BitAnd, BitOr, BitXor};
187impl BitAnd for Dynamic {
188    type Output = Self;
189    fn bitand(self, rhs: Self) -> Self::Output {
190        let ty = self.get_type() + rhs.get_type();
191        let left = ty.force(self).unwrap();
192        let right = ty.force(rhs).unwrap();
193        match (left, right) {
194            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l & r),
195            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l & r),
196            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l & r),
197            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l & r),
198            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l & r),
199            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l & r),
200            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l & r),
201            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l & r),
202            (_, _) => Dynamic::Null,
203        }
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210
211    #[test]
212    fn negating_signed_min_values_does_not_panic() {
213        assert_eq!(-Dynamic::I8(i8::MIN), Dynamic::I8(i8::MIN));
214        assert_eq!(-Dynamic::I16(i16::MIN), Dynamic::I16(i16::MIN));
215        assert_eq!(-Dynamic::I32(i32::MIN), Dynamic::I32(i32::MIN));
216        assert_eq!(-Dynamic::I64(i64::MIN), Dynamic::I64(i64::MIN));
217    }
218
219    #[test]
220    fn not_is_logical_for_bool_and_bitwise_for_ints() {
221        assert_eq!(!Dynamic::Bool(false), Dynamic::Bool(true));
222        assert_eq!(!Dynamic::I32(0b1010), Dynamic::I32(!0b1010));
223        assert_eq!(!Dynamic::U32(0b1010), Dynamic::U32(!0b1010));
224    }
225}
226
227impl BitOr for Dynamic {
228    type Output = Self;
229    fn bitor(self, rhs: Self) -> Self::Output {
230        let ty = self.get_type() + rhs.get_type();
231        let left = ty.force(self).unwrap();
232        let right = ty.force(rhs).unwrap();
233        match (left, right) {
234            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l | r),
235            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l | r),
236            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l | r),
237            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l | r),
238            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l | r),
239            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l | r),
240            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l | r),
241            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l | r),
242            (_, _) => Dynamic::Null,
243        }
244    }
245}
246
247impl BitXor for Dynamic {
248    type Output = Self;
249    fn bitxor(self, rhs: Self) -> Self::Output {
250        let ty = self.get_type() + rhs.get_type();
251        let left = ty.force(self).unwrap();
252        let right = ty.force(rhs).unwrap();
253        match (left, right) {
254            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l ^ r),
255            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l ^ r),
256            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l ^ r),
257            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l ^ r),
258            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l ^ r),
259            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l ^ r),
260            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l ^ r),
261            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l ^ r),
262            (_, _) => Dynamic::Null,
263        }
264    }
265}