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
40fn int_fault(reason: &'static str) -> Dynamic {
41    crate::set_fault(reason);
42    Dynamic::Null
43}
44
45fn checked_i64(left: &Dynamic, right: &Dynamic, reason: &'static str) -> Option<(i64, i64)> {
46    match (left.as_int(), right.as_int()) {
47        (Some(left), Some(right)) => Some((left, right)),
48        _ => {
49            crate::set_fault(reason);
50            None
51        }
52    }
53}
54
55impl Add for Dynamic {
56    type Output = Self;
57    fn add(self, rhs: Self) -> Self::Output {
58        if self.is_list() {
59            self.clone().append(rhs);
60            return self;
61        } else if rhs.is_list() {
62            rhs.clone().append(self);
63            return rhs;
64        }
65        match (self, rhs) {
66            (Self::StringBuf(mut left), Self::StringBuf(right)) => {
67                left.push_str(&right);
68                return Self::StringBuf(left);
69            }
70            (Self::StringBuf(mut left), Self::String(right)) => {
71                left.push_str(right.as_str());
72                return Self::StringBuf(left);
73            }
74            (Self::StringBuf(mut left), right) => {
75                left.push_str(&right.to_string());
76                return Self::StringBuf(left);
77            }
78            (Self::String(left), Self::StringBuf(right)) => {
79                let mut out = String::with_capacity(left.len() + right.len());
80                out.push_str(left.as_str());
81                out.push_str(&right);
82                return Self::StringBuf(out);
83            }
84            (Self::String(left), Self::String(right)) => {
85                let mut out = String::with_capacity(left.len() + right.len());
86                out.push_str(left.as_str());
87                out.push_str(right.as_str());
88                return Self::StringBuf(out);
89            }
90            (Self::String(left), right) => {
91                let right = right.to_string();
92                let mut out = String::with_capacity(left.len() + right.len());
93                out.push_str(left.as_str());
94                out.push_str(&right);
95                return Self::StringBuf(out);
96            }
97            (left, Self::StringBuf(right)) => {
98                let left = left.to_string();
99                let mut out = String::with_capacity(left.len() + right.len());
100                out.push_str(&left);
101                out.push_str(&right);
102                return Self::StringBuf(out);
103            }
104            (left, Self::String(right)) => {
105                let left = left.to_string();
106                let mut out = String::with_capacity(left.len() + right.len());
107                out.push_str(&left);
108                out.push_str(right.as_str());
109                return Self::StringBuf(out);
110            }
111            (left, right) => {
112                if left.is_f64() || right.is_f64() {
113                    return Dynamic::F64(left.as_float().unwrap_or(0.0) + right.as_float().unwrap_or(0.0));
114                } else if left.is_f32() || right.is_f32() {
115                    return Dynamic::F32(left.as_float().unwrap_or(0.0) as f32 + right.as_float().unwrap_or(0.0) as f32);
116                }
117                if left.is_int() || right.is_int() {
118                    let Some((left, right)) = checked_i64(&left, &right, "整数加法类型或范围错误") else {
119                        return Dynamic::Null;
120                    };
121                    return left.checked_add(right).map(Self::I64).unwrap_or_else(|| int_fault("整数加法溢出"));
122                }
123                if left.is_uint() || right.is_uint() {
124                    let (Some(left), Some(right)) = (left.as_uint(), right.as_uint()) else {
125                        return int_fault("无符号整数加法类型错误");
126                    };
127                    return left.checked_add(right).map(Self::U64).unwrap_or_else(|| int_fault("无符号整数加法溢出"));
128                }
129                if left.is_map() && right.is_map() {
130                    left.append(right);
131                }
132                left
133            }
134        }
135    }
136}
137
138impl Mul for Dynamic {
139    type Output = Self;
140    fn mul(self, rhs: Self) -> Self::Output {
141        if self.is_f64() || rhs.is_f64() {
142            return Dynamic::F64(self.as_float().unwrap_or(0.0) * rhs.as_float().unwrap_or(0.0));
143        } else if self.is_f32() || rhs.is_f32() {
144            return Dynamic::F32(self.as_float().unwrap_or(0.0) as f32 * rhs.as_float().unwrap_or(0.0) as f32);
145        }
146        if self.is_int() || rhs.is_int() {
147            let Some((left, right)) = checked_i64(&self, &rhs, "整数乘法类型或范围错误") else {
148                return Dynamic::Null;
149            };
150            return left.checked_mul(right).map(Self::I64).unwrap_or_else(|| int_fault("整数乘法溢出"));
151        }
152        if self.is_uint() || rhs.is_uint() {
153            let (Some(left), Some(right)) = (self.as_uint(), rhs.as_uint()) else {
154                return int_fault("无符号整数乘法类型错误");
155            };
156            return left.checked_mul(right).map(Self::U64).unwrap_or_else(|| int_fault("无符号整数乘法溢出"));
157        }
158        self
159    }
160}
161
162impl Sub for Dynamic {
163    type Output = Self;
164    fn sub(self, rhs: Self) -> Self::Output {
165        if self.is_float() && rhs.is_float() {
166            if self.is_f64() || rhs.is_f64() {
167                return Dynamic::F64(self.as_float().unwrap() - rhs.as_float().unwrap());
168            } else if self.is_f32() || rhs.is_f32() {
169                return Dynamic::F32(self.as_float().unwrap() as f32 - rhs.as_float().unwrap() as f32);
170            }
171        }
172        if self.is_int() || rhs.is_int() {
173            let Some((left, right)) = checked_i64(&self, &rhs, "整数减法类型或范围错误") else {
174                return Dynamic::Null;
175            };
176            return left.checked_sub(right).map(Self::I64).unwrap_or_else(|| int_fault("整数减法溢出"));
177        }
178        if self.is_uint() || rhs.is_uint() {
179            let (Some(left), Some(right)) = (self.as_uint(), rhs.as_uint()) else {
180                return int_fault("无符号整数减法类型错误");
181            };
182            return left.checked_sub(right).map(Self::U64).unwrap_or_else(|| int_fault("无符号整数减法溢出"));
183        }
184        self
185    }
186}
187
188impl Div for Dynamic {
189    type Output = Self;
190    fn div(self, rhs: Self) -> Self::Output {
191        if self.is_float() && rhs.is_float() {
192            if self.is_f64() || rhs.is_f64() {
193                return Dynamic::F64(self.as_float().unwrap() / rhs.as_float().unwrap());
194            } else if self.is_f32() || rhs.is_f32() {
195                return Dynamic::F32(self.as_float().unwrap() as f32 / rhs.as_float().unwrap() as f32);
196            }
197        }
198        if self.is_int() || rhs.is_int() {
199            let Some((left, right)) = checked_i64(&self, &rhs, "整数除法类型或范围错误") else {
200                return Dynamic::Null;
201            };
202            return match left.checked_div(right) {
203                Some(value) => Self::I64(value),
204                None => {
205                    crate::set_fault("整数除零");
206                    Self::Null
207                }
208            };
209        }
210        if self.is_uint() || rhs.is_uint() {
211            let (Some(left), Some(right)) = (self.as_uint(), rhs.as_uint()) else {
212                return int_fault("无符号整数除法类型错误");
213            };
214            return match left.checked_div(right) {
215                Some(value) => Self::U64(value),
216                None => {
217                    crate::set_fault("无符号整数除零");
218                    Self::Null
219                }
220            };
221        }
222        self
223    }
224}
225
226impl Rem for Dynamic {
227    type Output = Self;
228    fn rem(self, rhs: Self) -> Self::Output {
229        if self.is_int() || rhs.is_int() {
230            let Some((left, right)) = checked_i64(&self, &rhs, "整数取余类型或范围错误") else {
231                return Dynamic::Null;
232            };
233            return match left.checked_rem(right) {
234                Some(value) => Self::I64(value),
235                None => {
236                    crate::set_fault("整数取余除零");
237                    Self::Null
238                }
239            };
240        }
241        if self.is_uint() || rhs.is_uint() {
242            let (Some(left), Some(right)) = (self.as_uint(), rhs.as_uint()) else {
243                return int_fault("无符号整数取余类型错误");
244            };
245            return match left.checked_rem(right) {
246                Some(value) => Self::U64(value),
247                None => {
248                    crate::set_fault("无符号整数取余除零");
249                    Self::Null
250                }
251            };
252        }
253        self
254    }
255}
256
257use std::ops::{Shl, Shr};
258
259impl Shl for Dynamic {
260    type Output = Self;
261    fn shl(self, rhs: Self) -> Self::Output {
262        use Dynamic::*;
263        let Some(shift) = rhs.as_int().and_then(|value| u32::try_from(value).ok()).or_else(|| rhs.as_uint().and_then(|value| u32::try_from(value).ok())) else {
264            return int_fault("位移数量类型或范围错误");
265        };
266        match self {
267            I8(i) => i.checked_shl(shift).map(I8).unwrap_or_else(|| int_fault("左移溢出")),
268            I16(i) => i.checked_shl(shift).map(I16).unwrap_or_else(|| int_fault("左移溢出")),
269            I32(i) => i.checked_shl(shift).map(I32).unwrap_or_else(|| int_fault("左移溢出")),
270            I64(i) => i.checked_shl(shift).map(I64).unwrap_or_else(|| int_fault("左移溢出")),
271            U8(i) => i.checked_shl(shift).map(U8).unwrap_or_else(|| int_fault("左移溢出")),
272            U16(i) => i.checked_shl(shift).map(U16).unwrap_or_else(|| int_fault("左移溢出")),
273            U32(i) => i.checked_shl(shift).map(U32).unwrap_or_else(|| int_fault("左移溢出")),
274            U64(i) => i.checked_shl(shift).map(U64).unwrap_or_else(|| int_fault("左移溢出")),
275            _ => Dynamic::I64(0),
276        }
277    }
278}
279
280impl Shr for Dynamic {
281    type Output = Self;
282    fn shr(self, rhs: Self) -> Self::Output {
283        use Dynamic::*;
284        let Some(shift) = rhs.as_int().and_then(|value| u32::try_from(value).ok()).or_else(|| rhs.as_uint().and_then(|value| u32::try_from(value).ok())) else {
285            return int_fault("位移数量类型或范围错误");
286        };
287        match self {
288            I8(i) => i.checked_shr(shift).map(I8).unwrap_or_else(|| int_fault("右移溢出")),
289            I16(i) => i.checked_shr(shift).map(I16).unwrap_or_else(|| int_fault("右移溢出")),
290            I32(i) => i.checked_shr(shift).map(I32).unwrap_or_else(|| int_fault("右移溢出")),
291            I64(i) => i.checked_shr(shift).map(I64).unwrap_or_else(|| int_fault("右移溢出")),
292            U8(i) => i.checked_shr(shift).map(U8).unwrap_or_else(|| int_fault("右移溢出")),
293            U16(i) => i.checked_shr(shift).map(U16).unwrap_or_else(|| int_fault("右移溢出")),
294            U32(i) => i.checked_shr(shift).map(U32).unwrap_or_else(|| int_fault("右移溢出")),
295            U64(i) => i.checked_shr(shift).map(U64).unwrap_or_else(|| int_fault("右移溢出")),
296            _ => Dynamic::I64(0),
297        }
298    }
299}
300
301use std::ops::{BitAnd, BitOr, BitXor};
302impl BitAnd for Dynamic {
303    type Output = Self;
304    fn bitand(self, rhs: Self) -> Self::Output {
305        let ty = self.get_type() + rhs.get_type();
306        let Ok(left) = ty.force(self) else {
307            return int_fault("按位与左操作数类型错误");
308        };
309        let Ok(right) = ty.force(rhs) else {
310            return int_fault("按位与右操作数类型错误");
311        };
312        match (left, right) {
313            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l & r),
314            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l & r),
315            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l & r),
316            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l & r),
317            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l & r),
318            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l & r),
319            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l & r),
320            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l & r),
321            (_, _) => Dynamic::Null,
322        }
323    }
324}
325
326#[cfg(test)]
327mod tests {
328    use super::*;
329
330    #[test]
331    fn negating_signed_min_values_does_not_panic() {
332        assert_eq!(-Dynamic::I8(i8::MIN), Dynamic::I8(i8::MIN));
333        assert_eq!(-Dynamic::I16(i16::MIN), Dynamic::I16(i16::MIN));
334        assert_eq!(-Dynamic::I32(i32::MIN), Dynamic::I32(i32::MIN));
335        assert_eq!(-Dynamic::I64(i64::MIN), Dynamic::I64(i64::MIN));
336    }
337
338    #[test]
339    fn not_is_logical_for_bool_and_bitwise_for_ints() {
340        assert_eq!(!Dynamic::Bool(false), Dynamic::Bool(true));
341        assert_eq!(!Dynamic::I32(0b1010), Dynamic::I32(!0b1010));
342        assert_eq!(!Dynamic::U32(0b1010), Dynamic::U32(!0b1010));
343    }
344}
345
346impl BitOr for Dynamic {
347    type Output = Self;
348    fn bitor(self, rhs: Self) -> Self::Output {
349        let ty = self.get_type() + rhs.get_type();
350        let Ok(left) = ty.force(self) else {
351            return int_fault("按位或左操作数类型错误");
352        };
353        let Ok(right) = ty.force(rhs) else {
354            return int_fault("按位或右操作数类型错误");
355        };
356        match (left, right) {
357            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l | r),
358            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l | r),
359            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l | r),
360            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l | r),
361            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l | r),
362            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l | r),
363            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l | r),
364            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l | r),
365            (_, _) => Dynamic::Null,
366        }
367    }
368}
369
370impl BitXor for Dynamic {
371    type Output = Self;
372    fn bitxor(self, rhs: Self) -> Self::Output {
373        let ty = self.get_type() + rhs.get_type();
374        let Ok(left) = ty.force(self) else {
375            return int_fault("按位异或左操作数类型错误");
376        };
377        let Ok(right) = ty.force(rhs) else {
378            return int_fault("按位异或右操作数类型错误");
379        };
380        match (left, right) {
381            (Dynamic::I8(l), Dynamic::I8(r)) => Dynamic::I8(l ^ r),
382            (Dynamic::I16(l), Dynamic::I16(r)) => Dynamic::I16(l ^ r),
383            (Dynamic::I32(l), Dynamic::I32(r)) => Dynamic::I32(l ^ r),
384            (Dynamic::I64(l), Dynamic::I64(r)) => Dynamic::I64(l ^ r),
385            (Dynamic::U8(l), Dynamic::U8(r)) => Dynamic::U8(l ^ r),
386            (Dynamic::U16(l), Dynamic::U16(r)) => Dynamic::U16(l ^ r),
387            (Dynamic::U32(l), Dynamic::U32(r)) => Dynamic::U32(l ^ r),
388            (Dynamic::U64(l), Dynamic::U64(r)) => Dynamic::U64(l ^ r),
389            (_, _) => Dynamic::Null,
390        }
391    }
392}