1use crate::{Typ, ValArray, Value};
2use arcstr::literal;
3use compact_str::format_compact;
4use rust_decimal::Decimal;
5use std::{
6 cmp::{Ordering, PartialEq, PartialOrd},
7 hash::Hash,
8 iter, mem,
9 ops::{Add, Div, Mul, Not, Rem, Sub},
10 time::Duration,
11};
12use triomphe::Arc;
13
14impl Hash for Value {
15 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
16 use std::num::FpCategory::*;
17 match self {
18 Value::U32(v) => {
19 0u8.hash(state);
20 v.hash(state)
21 }
22 Value::V32(v) => {
23 1u8.hash(state);
24 v.hash(state)
25 }
26 Value::I32(v) => {
27 2u8.hash(state);
28 v.hash(state)
29 }
30 Value::Z32(v) => {
31 3u8.hash(state);
32 v.hash(state)
33 }
34 Value::U64(v) => {
35 4u8.hash(state);
36 v.hash(state)
37 }
38 Value::V64(v) => {
39 5u8.hash(state);
40 v.hash(state)
41 }
42 Value::I64(v) => {
43 6u8.hash(state);
44 v.hash(state)
45 }
46 Value::Z64(v) => {
47 7u8.hash(state);
48 v.hash(state)
49 }
50 Value::F32(v) => {
51 8u8.hash(state);
52 let bits = v.to_bits();
53 match v.classify() {
54 Nan => ((bits & 0xFF00_0000) | 0x1).hash(state), _ => bits.hash(state),
56 }
57 }
58 Value::F64(v) => {
59 9u8.hash(state);
60 let bits = v.to_bits();
61 match v.classify() {
62 Nan => ((bits & 0xFFE0_0000_0000_0000) | 0x1).hash(state), _ => bits.hash(state),
64 }
65 }
66 Value::DateTime(d) => {
67 10u8.hash(state);
68 d.hash(state)
69 }
70 Value::Duration(d) => {
71 11u8.hash(state);
72 d.hash(state)
73 }
74 Value::String(c) => {
75 12u8.hash(state);
76 c.hash(state)
77 }
78 Value::Bytes(b) => {
79 13u8.hash(state);
80 b.hash(state)
81 }
82 Value::Bool(true) => 14u8.hash(state),
83 Value::Bool(false) => 15u8.hash(state),
84 Value::Null => 16u8.hash(state),
85 Value::Error(c) => match &**c {
86 Value::String(e) => {
87 18u8.hash(state);
88 e.hash(state)
89 }
90 v => {
91 21u8.hash(state);
92 v.hash(state)
93 }
94 },
95 Value::Array(a) => {
96 19u8.hash(state);
97 for v in a.iter() {
98 v.hash(state)
99 }
100 }
101 Value::Decimal(d) => {
102 20u8.hash(state);
103 d.hash(state);
104 }
105 Value::Map(m) => {
106 21u8.hash(state);
107 m.hash(state);
108 }
109 Value::U8(v) => {
110 22u8.hash(state);
111 v.hash(state)
112 }
113 Value::I8(v) => {
114 23u8.hash(state);
115 v.hash(state)
116 }
117 Value::U16(v) => {
118 24u8.hash(state);
119 v.hash(state)
120 }
121 Value::I16(v) => {
122 25u8.hash(state);
123 v.hash(state)
124 }
125 Value::Abstract(v) => {
126 26u8.hash(state);
127 v.hash(state)
128 }
129 }
130 }
131}
132
133impl PartialEq for Value {
134 fn eq(&self, rhs: &Value) -> bool {
135 use std::num::FpCategory::*;
136 Typ::get(self) == Typ::get(rhs)
137 && match (self, rhs) {
138 (Value::U8(l), Value::U8(r)) => l == r,
139 (Value::I8(l), Value::I8(r)) => l == r,
140 (Value::U16(l), Value::U16(r)) => l == r,
141 (Value::I16(l), Value::I16(r)) => l == r,
142 (Value::U32(l), Value::U32(r)) => l == r,
143 (Value::V32(l), Value::V32(r)) => l == r,
144 (Value::I32(l), Value::I32(r)) => l == r,
145 (Value::Z32(l), Value::Z32(r)) => l == r,
146 (Value::U64(l), Value::U64(r)) => l == r,
147 (Value::V64(l), Value::V64(r)) => l == r,
148 (Value::I64(l), Value::I64(r)) => l == r,
149 (Value::Z64(l), Value::Z64(r)) => l == r,
150 (Value::F32(l), Value::F32(r)) => match (l.classify(), r.classify()) {
151 (Nan, Nan) => true,
152 (_, _) => l == r,
153 },
154 (Value::F64(l), Value::F64(r)) => match (l.classify(), r.classify()) {
155 (Nan, Nan) => true,
156 (_, _) => l == r,
157 },
158 (Value::Decimal(l), Value::Decimal(r)) => l == r,
159 (Value::DateTime(l), Value::DateTime(r)) => l == r,
160 (Value::Duration(l), Value::Duration(r)) => l == r,
161 (Value::Bool(l), Value::Bool(r)) => l == r,
162 (Value::Null, Value::Null) => true,
163 (Value::String(l), Value::String(r)) => l == r,
164 (Value::Bytes(l), Value::Bytes(r)) => l == r,
165 (Value::Error(l), Value::Error(r)) => l == r,
166 (Value::Array(l), Value::Array(r)) => l == r,
167 (Value::Map(l), Value::Map(r)) => l == r,
168 (Value::Abstract(l), Value::Abstract(r)) => l == r,
169 (_, _) => false,
170 }
171 }
172}
173
174impl Eq for Value {}
175
176impl PartialOrd for Value {
177 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
178 use std::num::FpCategory::*;
179 match Typ::get(self).cmp(&Typ::get(other)) {
180 Ordering::Greater => Some(Ordering::Greater),
181 Ordering::Less => Some(Ordering::Less),
182 Ordering::Equal => match (self, other) {
183 (Value::U8(l), Value::U8(r)) => l.partial_cmp(r),
184 (Value::I8(l), Value::I8(r)) => l.partial_cmp(r),
185 (Value::U16(l), Value::U16(r)) => l.partial_cmp(r),
186 (Value::I16(l), Value::I16(r)) => l.partial_cmp(r),
187 (Value::U32(l), Value::U32(r)) => l.partial_cmp(r),
188 (Value::V32(l), Value::V32(r)) => l.partial_cmp(r),
189 (Value::I32(l), Value::I32(r)) => l.partial_cmp(r),
190 (Value::Z32(l), Value::Z32(r)) => l.partial_cmp(r),
191 (Value::U64(l), Value::U64(r)) => l.partial_cmp(r),
192 (Value::V64(l), Value::V64(r)) => l.partial_cmp(r),
193 (Value::I64(l), Value::I64(r)) => l.partial_cmp(r),
194 (Value::Z64(l), Value::Z64(r)) => l.partial_cmp(r),
195 (Value::F32(l), Value::F32(r)) => match (l.classify(), r.classify()) {
196 (Nan, Nan) => Some(Ordering::Equal),
197 (Nan, _) => Some(Ordering::Less),
198 (_, Nan) => Some(Ordering::Greater),
199 (_, _) => l.partial_cmp(r),
200 },
201 (Value::F64(l), Value::F64(r)) => match (l.classify(), r.classify()) {
202 (Nan, Nan) => Some(Ordering::Equal),
203 (Nan, _) => Some(Ordering::Less),
204 (_, Nan) => Some(Ordering::Greater),
205 (_, _) => l.partial_cmp(r),
206 },
207 (Value::Decimal(l), Value::Decimal(r)) => l.partial_cmp(r),
208 (Value::DateTime(l), Value::DateTime(r)) => l.partial_cmp(r),
209 (Value::Duration(l), Value::Duration(r)) => l.partial_cmp(r),
210 (Value::Bool(l), Value::Bool(r)) => l.partial_cmp(r),
211 (Value::Null, Value::Null) => Some(Ordering::Equal),
212 (Value::String(l), Value::String(r)) => l.partial_cmp(r),
213 (Value::Bytes(l), Value::Bytes(r)) => l.partial_cmp(r),
214 (Value::Error(l), Value::Error(r)) => l.partial_cmp(r),
215 (Value::Array(l), Value::Array(r)) => l.partial_cmp(r),
216 (Value::Map(l), Value::Map(r)) => l.partial_cmp(r),
217 (Value::Abstract(l), Value::Abstract(r)) => l.partial_cmp(r),
218 (_, _) => unreachable!(),
219 },
220 }
221 }
222}
223
224impl Ord for Value {
225 fn cmp(&self, other: &Self) -> Ordering {
226 self.partial_cmp(other).unwrap()
227 }
228}
229
230macro_rules! int_op {
231 ($lhs:expr, wrapping, $method:ident, $rhs:expr, $Ctor:ident) => {
232 Value::$Ctor(($lhs).$method($rhs))
233 };
234 ($lhs:expr, checked, $method:ident, $rhs:expr, $Ctor:ident) => {
235 match ($lhs).$method($rhs) {
236 Some(v) => Value::$Ctor(v),
237 None => return Value::error(literal!("arithmetic error")),
238 }
239 };
240}
241
242macro_rules! checked_decimal {
243 ($lhs:expr, $dec_method:ident, $rhs:expr) => {
244 match ($lhs).$dec_method($rhs) {
245 Some(v) => Value::Decimal(Arc::new(v)),
246 None => return Value::error(literal!("decimal arithmetic error")),
247 }
248 };
249}
250
251macro_rules! checked_dur {
252 ($expr:expr) => {
253 match $expr {
254 Some(v) => Value::Duration(Arc::new(v)),
255 None => return Value::error(literal!("duration arithmetic error")),
256 }
257 };
258}
259
260macro_rules! dur_from_f64 {
261 ($expr:expr) => {
262 match Duration::try_from_secs_f64($expr) {
263 Ok(v) => Value::Duration(Arc::new(v)),
264 Err(_) => return Value::error(literal!("duration arithmetic error")),
265 }
266 };
267}
268
269macro_rules! apply_op_mixed_int {
270 ($lhs:expr, $rhs:expr, $lhc:ident, $lht:ty, $op:tt, $mode:ident, $int_method:ident, $dec_method:ident) => {
271 match $rhs {
272 Value::U8(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
273 Value::I8(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
274 Value::U16(r) if mem::size_of::<u16>() > mem::size_of::<$lht>() => int_op!(($lhs as u16), $mode, $int_method, r, U16),
275 Value::U16(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
276 Value::I16(r) if mem::size_of::<i16>() > mem::size_of::<$lht>() => int_op!(($lhs as i16), $mode, $int_method, r, I16),
277 Value::I16(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
278 Value::U32(r) | Value::V32(r) if mem::size_of::<u32>() > mem::size_of::<$lht>() => int_op!(($lhs as u32), $mode, $int_method, r, U32),
279 Value::U32(r) | Value::V32(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
280 Value::I32(r) | Value::Z32(r) if mem::size_of::<i32>() > mem::size_of::<$lht>() => int_op!(($lhs as i32), $mode, $int_method, r, I32),
281 Value::I32(r) | Value::Z32(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
282 Value::U64(r) | Value::V64(r) if mem::size_of::<u64>() > mem::size_of::<$lht>() => int_op!(($lhs as u64), $mode, $int_method, r, U64),
283 Value::U64(r) | Value::V64(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
284 Value::I64(r) | Value::Z64(r) if mem::size_of::<i64>() > mem::size_of::<$lht>() => int_op!(($lhs as i64), $mode, $int_method, r, I64),
285 Value::I64(r) | Value::Z64(r) => int_op!($lhs, $mode, $int_method, r as $lht, $lhc),
286 Value::F32(r) => Value::F32(($lhs as f32) $op r),
287 Value::F64(r) => Value::F64(($lhs as f64) $op r),
288 Value::Decimal(r) => checked_decimal!(Decimal::from($lhs), $dec_method, *r),
289 _ => unreachable!(),
290 }
291 }
292}
293
294macro_rules! apply_op_mixed_float {
295 ($lhs:expr, $rhs:expr, $lhc:ident, $lht:ty, $op:tt, $dec_method:ident) => {
296 match $rhs {
297 Value::U8(r) => Value::$lhc($lhs $op r as $lht),
298 Value::I8(r) => Value::$lhc($lhs $op r as $lht),
299 Value::U16(r) => Value::$lhc($lhs $op r as $lht),
300 Value::I16(r) => Value::$lhc($lhs $op r as $lht),
301 Value::U32(r) | Value::V32(r) => Value::$lhc($lhs $op r as $lht),
302 Value::I32(r) | Value::Z32(r) => Value::$lhc($lhs $op r as $lht),
303 Value::U64(r) | Value::V64(r) => Value::$lhc($lhs $op r as $lht),
304 Value::I64(r) | Value::Z64(r) => Value::$lhc($lhs $op r as $lht),
305 Value::F32(r) => Value::$lhc($lhs $op r as $lht),
306 Value::F64(r) => Value::$lhc($lhs $op r as $lht),
307 Value::Decimal(r) => {
308 let d = match Decimal::try_from($lhs) {
309 Err(e) => return Value::error(format!("could not convert {e:?} to decimal")),
310 Ok(d) => d
311 };
312 checked_decimal!(d, $dec_method, *r)
313 },
314 _ => unreachable!(),
315 }
316 }
317}
318
319macro_rules! apply_op_mixed_decimal {
320 ($lhs:expr, $rhs:expr, $dec_method:ident) => {
321 match $rhs {
322 Value::U8(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
323 Value::I8(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
324 Value::U16(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
325 Value::I16(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
326 Value::U32(r) | Value::V32(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
327 Value::I32(r) | Value::Z32(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
328 Value::U64(r) | Value::V64(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
329 Value::I64(r) | Value::Z64(r) => checked_decimal!($lhs, $dec_method, Decimal::from(r)),
330 Value::F32(r) => {
331 let d = match Decimal::try_from(r) {
332 Err(e) => return Value::error(format!("could not convert {e:?} to decimal")),
333 Ok(d) => d
334 };
335 checked_decimal!($lhs, $dec_method, d)
336 },
337 Value::F64(r) => {
338 let d = match Decimal::try_from(r) {
339 Err(e) => return Value::error(format!("could not convert {e:?} to decimal")),
340 Ok(d) => d
341 };
342 checked_decimal!($lhs, $dec_method, d)
343 }
344 _ => unreachable!(),
345 }
346 }
347}
348
349macro_rules! number {
350 () => {
351 Value::U8(_)
352 | Value::I8(_)
353 | Value::U16(_)
354 | Value::I16(_)
355 | Value::U32(_)
356 | Value::V32(_)
357 | Value::I32(_)
358 | Value::Z32(_)
359 | Value::U64(_)
360 | Value::V64(_)
361 | Value::I64(_)
362 | Value::Z64(_)
363 | Value::F32(_)
364 | Value::F64(_)
365 | Value::Decimal(_)
366 };
367}
368
369macro_rules! apply_op {
370 ($self:expr, $rhs:expr, $id:expr, $op:tt, $mode:ident, $int_method:ident, $dec_method:ident, $($pat:pat => $blk:block),+) => {
371 #[allow(unreachable_patterns)]
372 match ($self, $rhs) {
373 (Value::U8(l), Value::U8(r)) => int_op!(l, $mode, $int_method, r, U8),
374 (Value::I8(l), Value::I8(r)) => int_op!(l, $mode, $int_method, r, I8),
375 (Value::U16(l), Value::U16(r)) => int_op!(l, $mode, $int_method, r, U16),
376 (Value::I16(l), Value::I16(r)) => int_op!(l, $mode, $int_method, r, I16),
377 (Value::U32(l) | Value::V32(l), Value::U32(r) | Value::V32(r)) => {
378 int_op!(l, $mode, $int_method, r, U32)
379 }
380 (Value::I32(l) | Value::Z32(l), Value::I32(r) | Value::Z32(r)) => {
381 int_op!(l, $mode, $int_method, r, I32)
382 }
383 (Value::U64(l) | Value::V64(l), Value::U64(r) | Value::V64(r)) => {
384 int_op!(l, $mode, $int_method, r, U64)
385 }
386 (Value::I64(l) | Value::Z64(l), Value::I64(r) | Value::Z64(r)) => {
387 int_op!(l, $mode, $int_method, r, I64)
388 }
389 (Value::F32(l), Value::F32(r)) => Value::F32(l $op r),
390 (Value::F64(l), Value::F64(r)) => Value::F64(l $op r),
391 (Value::Decimal(l), Value::Decimal(r)) => checked_decimal!(*l, $dec_method, *r),
392 (Value::U8(l), v@ number!()) => apply_op_mixed_int!(l, v, U8, u8, $op, $mode, $int_method, $dec_method),
393 (Value::I8(l), v@ number!()) => apply_op_mixed_int!(l, v, I8, i8, $op, $mode, $int_method, $dec_method),
394 (Value::U16(l), v@ number!()) => apply_op_mixed_int!(l, v, U16, u16, $op, $mode, $int_method, $dec_method),
395 (Value::I16(l), v@ number!()) => apply_op_mixed_int!(l, v, I16, i16, $op, $mode, $int_method, $dec_method),
396 (Value::U32(l) | Value::V32(l), v@ number!()) => apply_op_mixed_int!(l, v, U32, u32, $op, $mode, $int_method, $dec_method),
397 (Value::I32(l) | Value::Z32(l), v@ number!()) => apply_op_mixed_int!(l, v, I32, i32, $op, $mode, $int_method, $dec_method),
398 (Value::U64(l) | Value::V64(l), v@ number!()) => apply_op_mixed_int!(l, v, U64, u64, $op, $mode, $int_method, $dec_method),
399 (Value::I64(l) | Value::Z64(l), v@ number!()) => apply_op_mixed_int!(l, v, I64, i64, $op, $mode, $int_method, $dec_method),
400 (Value::F32(l), v@ number!()) => apply_op_mixed_float!(l, v, F32, f32, $op, $dec_method),
401 (Value::F64(l), v@ number!()) => apply_op_mixed_float!(l, v, F64, f64, $op, $dec_method),
402 (Value::Decimal(l), v@ number!()) => apply_op_mixed_decimal!(*l, v, $dec_method),
403 (Value::String(s), n) => match s.parse::<Value>() {
404 Err(e) => Value::error(format_compact!("{}", e).as_str()),
405 Ok(s) => s $op n,
406 }
407 (n, Value::String(s)) => match s.parse::<Value>() {
408 Err(e) => Value::error(format_compact!("{}", e).as_str()),
409 Ok(s) => n $op s,
410 },
411 (Value::Array(e0), Value::Array(e1)) => {
412 let (e0, e1) = if e0.len() < e1.len() { (e0, e1) } else { (e1, e0) };
413 let iter = e0
414 .iter()
415 .cloned()
416 .chain(iter::repeat(Value::F64($id)))
417 .zip(e1.iter().cloned());
418 Value::Array(iter.map(|(v0, v1)| v0 $op v1).collect())
419 }
420 (l @ Value::Array(_), n) => {
421 match n.cast(Typ::Array) {
422 None => Value::error(literal!("can't add to array")),
423 Some(r) => l $op r,
424 }
425 }
426 (n, r @ Value::Array(_)) => {
427 match n.cast(Typ::Array) {
428 None => Value::error(literal!("can't add to array")),
429 Some(l) => l $op r,
430 }
431 }
432 (Value::Map(_), _) | (_, Value::Map(_)) => Value::error(literal!("can't apply to Map")),
433 (Value::Bytes(_), _) | (_, Value::Bytes(_)) => {
434 Value::error(literal!("can't add bytes"))
435 }
436 (Value::Null, _) | (_, Value::Null) => {
437 Value::error(literal!("can't add null"))
438 }
439 | (Value::Error(_), _)
440 | (_, Value::Error(_)) => Value::error(literal!("can't add error types")),
441 (Value::Abstract(_), _) | (_, Value::Abstract(_)) => Value::error(literal!("can't add abstract types")),
442 (Value::Bool(true), n) => Value::U32(1) $op n,
443 (n, Value::Bool(true)) => n $op Value::U32(1),
444 (Value::Bool(false), n) => Value::U32(0) $op n,
445 (n, Value::Bool(false)) => n $op Value::U32(0),
446 $($pat => $blk),+
447 }
448 }
449}
450
451impl Add for Value {
452 type Output = Value;
453
454 fn add(self, rhs: Self) -> Self {
455 apply_op!(
456 self, rhs, 0., +, wrapping, wrapping_add, checked_add,
457 (Value::DateTime(dt), Value::Duration(d))
458 | (Value::Duration(d), Value::DateTime(dt)) => {
459 match chrono::Duration::from_std(*d) {
460 Ok(d) => Value::DateTime(Arc::new((*dt) + d)),
461 Err(e) => Value::error(format_compact!("{}", e).as_str()),
462 }
463 },
464 (Value::Duration(d0), Value::Duration(d1)) => {
465 checked_dur!(d0.checked_add(*d1))
466 },
467 (Value::Duration(_), _)
468 | (_, Value::Duration(_))
469 | (_, Value::DateTime(_))
470 | (Value::DateTime(_), _) => {
471 Value::error(literal!("can't add to datetime/duration"))
472 }
473 )
474 }
475}
476
477impl Sub for Value {
478 type Output = Value;
479
480 fn sub(self, rhs: Self) -> Self {
481 apply_op!(
482 self, rhs, 0., -, wrapping, wrapping_sub, checked_sub,
483 (Value::DateTime(dt), Value::Duration(d))
484 | (Value::Duration(d), Value::DateTime(dt)) => {
485 match chrono::Duration::from_std(*d) {
486 Ok(d) => Value::DateTime(Arc::new((*dt) - d)),
487 Err(e) => Value::error(format_compact!("{}", e).as_str()),
488 }
489 },
490 (Value::Duration(d0), Value::Duration(d1)) => {
491 checked_dur!(d0.checked_sub(*d1))
492 },
493 (Value::Duration(_), _)
494 | (_, Value::Duration(_))
495 | (_, Value::DateTime(_))
496 | (Value::DateTime(_), _) => {
497 Value::error(literal!("can't sub datetime/duration"))
498 }
499 )
500 }
501}
502
503impl Mul for Value {
504 type Output = Value;
505
506 fn mul(self, rhs: Self) -> Self {
507 apply_op!(
508 self, rhs, 1., *, wrapping, wrapping_mul, checked_mul,
509 (Value::Duration(d), Value::U32(n) | Value::V32(n))
510 | (Value::U32(n) | Value::V32(n), Value::Duration(d)) => {
511 checked_dur!(d.checked_mul(n))
512 },
513 (Value::Duration(d), Value::I32(n) | Value::Z32(n))
514 | (Value::I32(n) | Value::Z32(n), Value::Duration(d)) => {
515 if n < 0 { return Value::error(literal!("can't multiply duration by negative")); }
516 checked_dur!(d.checked_mul(n as u32))
517 },
518 (Value::Duration(d), Value::U64(n) | Value::V64(n))
519 | (Value::U64(n) | Value::V64(n), Value::Duration(d)) => {
520 checked_dur!(d.checked_mul(n as u32))
521 },
522 (Value::Duration(d), Value::I64(n) | Value::Z64(n))
523 | (Value::I64(n) | Value::Z64(n), Value::Duration(d)) => {
524 if n < 0 { return Value::error(literal!("can't multiply duration by negative")); }
525 checked_dur!(d.checked_mul(n as u32))
526 },
527 (Value::Duration(d), Value::F32(s)) | (Value::F32(s), Value::Duration(d)) => {
528 dur_from_f64!(d.as_secs_f64() * s as f64)
529 },
530 (Value::Duration(d), Value::F64(s)) | (Value::F64(s), Value::Duration(d)) => {
531 dur_from_f64!(d.as_secs_f64() * s)
532 },
533 | (Value::Duration(_), _)
534 | (_, Value::Duration(_))
535 | (_, Value::DateTime(_))
536 | (Value::DateTime(_), _) => {
537 Value::error(literal!("can't mul datetime/duration"))
538 }
539 )
540 }
541}
542
543impl Div for Value {
544 type Output = Value;
545
546 fn div(self, rhs: Self) -> Self {
547 apply_op!(
548 self, rhs, 1., /, checked, checked_div, checked_div,
549 (Value::Duration(d), Value::U32(s) | Value::V32(s)) => {
550 checked_dur!(d.checked_div(s))
551 },
552 (Value::Duration(d), Value::I32(s) | Value::Z32(s)) => {
553 if s < 0 { return Value::error(literal!("can't divide duration by negative")); }
554 checked_dur!(d.checked_div(s as u32))
555 },
556 (Value::Duration(d), Value::U64(s) | Value::V64(s)) => {
557 checked_dur!(d.checked_div(s as u32))
558 },
559 (Value::Duration(d), Value::I64(s) | Value::Z64(s)) => {
560 if s < 0 { return Value::error(literal!("can't divide duration by negative")); }
561 checked_dur!(d.checked_div(s as u32))
562 },
563 (Value::Duration(d), Value::F32(s)) => {
564 dur_from_f64!(d.as_secs_f64() / s as f64)
565 },
566 (Value::Duration(d), Value::F64(s)) => {
567 dur_from_f64!(d.as_secs_f64() / s)
568 },
569 (Value::Duration(_), _)
570 | (_, Value::Duration(_))
571 | (_, Value::DateTime(_))
572 | (Value::DateTime(_), _) => {
573 Value::error(literal!("can't div datetime/duration"))
574 }
575 )
576 }
577}
578
579impl Rem for Value {
580 type Output = Value;
581
582 fn rem(self, rhs: Self) -> Self::Output {
583 apply_op!(
584 self, rhs, 1., %, checked, checked_rem, checked_rem,
585 (Value::Duration(_), _)
586 | (_, Value::Duration(_))
587 | (_, Value::DateTime(_))
588 | (Value::DateTime(_), _) => {
589 Value::error(literal!("can't mod datetime/duration"))
590 }
591 )
592 }
593}
594
595impl Value {
596 pub fn checked_add(self, rhs: Self) -> Self {
597 apply_op!(
598 self, rhs, 0., +, checked, checked_add, checked_add,
599 (Value::DateTime(dt), Value::Duration(d))
600 | (Value::Duration(d), Value::DateTime(dt)) => {
601 match chrono::Duration::from_std(*d) {
602 Ok(d) => Value::DateTime(Arc::new((*dt) + d)),
603 Err(e) => Value::error(format_compact!("{}", e).as_str()),
604 }
605 },
606 (Value::Duration(d0), Value::Duration(d1)) => {
607 checked_dur!(d0.checked_add(*d1))
608 },
609 (Value::Duration(_), _)
610 | (_, Value::Duration(_))
611 | (_, Value::DateTime(_))
612 | (Value::DateTime(_), _) => {
613 Value::error(literal!("can't add to datetime/duration"))
614 }
615 )
616 }
617
618 pub fn checked_sub(self, rhs: Self) -> Self {
619 apply_op!(
620 self, rhs, 0., -, checked, checked_sub, checked_sub,
621 (Value::DateTime(dt), Value::Duration(d))
622 | (Value::Duration(d), Value::DateTime(dt)) => {
623 match chrono::Duration::from_std(*d) {
624 Ok(d) => Value::DateTime(Arc::new((*dt) - d)),
625 Err(e) => Value::error(format_compact!("{}", e).as_str()),
626 }
627 },
628 (Value::Duration(d0), Value::Duration(d1)) => {
629 checked_dur!(d0.checked_sub(*d1))
630 },
631 (Value::Duration(_), _)
632 | (_, Value::Duration(_))
633 | (_, Value::DateTime(_))
634 | (Value::DateTime(_), _) => {
635 Value::error(literal!("can't sub datetime/duration"))
636 }
637 )
638 }
639
640 pub fn checked_mul(self, rhs: Self) -> Self {
641 apply_op!(
642 self, rhs, 1., *, checked, checked_mul, checked_mul,
643 (Value::Duration(d), Value::U32(n) | Value::V32(n))
644 | (Value::U32(n) | Value::V32(n), Value::Duration(d)) => {
645 checked_dur!(d.checked_mul(n))
646 },
647 (Value::Duration(d), Value::I32(n) | Value::Z32(n))
648 | (Value::I32(n) | Value::Z32(n), Value::Duration(d)) => {
649 if n < 0 { return Value::error(literal!("can't multiply duration by negative")); }
650 checked_dur!(d.checked_mul(n as u32))
651 },
652 (Value::Duration(d), Value::U64(n) | Value::V64(n))
653 | (Value::U64(n) | Value::V64(n), Value::Duration(d)) => {
654 checked_dur!(d.checked_mul(n as u32))
655 },
656 (Value::Duration(d), Value::I64(n) | Value::Z64(n))
657 | (Value::I64(n) | Value::Z64(n), Value::Duration(d)) => {
658 if n < 0 { return Value::error(literal!("can't multiply duration by negative")); }
659 checked_dur!(d.checked_mul(n as u32))
660 },
661 (Value::Duration(d), Value::F32(s)) | (Value::F32(s), Value::Duration(d)) => {
662 dur_from_f64!(d.as_secs_f64() * s as f64)
663 },
664 (Value::Duration(d), Value::F64(s)) | (Value::F64(s), Value::Duration(d)) => {
665 dur_from_f64!(d.as_secs_f64() * s)
666 },
667 | (Value::Duration(_), _)
668 | (_, Value::Duration(_))
669 | (_, Value::DateTime(_))
670 | (Value::DateTime(_), _) => {
671 Value::error(literal!("can't mul datetime/duration"))
672 }
673 )
674 }
675
676 pub fn checked_div(self, rhs: Self) -> Self {
677 apply_op!(
678 self, rhs, 1., /, checked, checked_div, checked_div,
679 (Value::Duration(d), Value::U32(s) | Value::V32(s)) => {
680 checked_dur!(d.checked_div(s))
681 },
682 (Value::Duration(d), Value::I32(s) | Value::Z32(s)) => {
683 if s < 0 { return Value::error(literal!("can't divide duration by negative")); }
684 checked_dur!(d.checked_div(s as u32))
685 },
686 (Value::Duration(d), Value::U64(s) | Value::V64(s)) => {
687 checked_dur!(d.checked_div(s as u32))
688 },
689 (Value::Duration(d), Value::I64(s) | Value::Z64(s)) => {
690 if s < 0 { return Value::error(literal!("can't divide duration by negative")); }
691 checked_dur!(d.checked_div(s as u32))
692 },
693 (Value::Duration(d), Value::F32(s)) => {
694 dur_from_f64!(d.as_secs_f64() / s as f64)
695 },
696 (Value::Duration(d), Value::F64(s)) => {
697 dur_from_f64!(d.as_secs_f64() / s)
698 },
699 (Value::Duration(_), _)
700 | (_, Value::Duration(_))
701 | (_, Value::DateTime(_))
702 | (Value::DateTime(_), _) => {
703 Value::error(literal!("can't div datetime/duration"))
704 }
705 )
706 }
707
708 pub fn checked_rem(self, rhs: Self) -> Self {
709 apply_op!(
710 self, rhs, 1., %, checked, checked_rem, checked_rem,
711 (Value::Duration(_), _)
712 | (_, Value::Duration(_))
713 | (_, Value::DateTime(_))
714 | (Value::DateTime(_), _) => {
715 Value::error(literal!("can't mod datetime/duration"))
716 }
717 )
718 }
719}
720
721impl Not for Value {
722 type Output = Value;
723
724 fn not(self) -> Self {
725 match self {
726 Value::Bool(v) => Value::Bool(!v),
727 Value::Null => Value::Null,
728 Value::U8(v) => Value::U8(!v),
729 Value::I8(v) => Value::I8(!v),
730 Value::U16(v) => Value::U16(!v),
731 Value::I16(v) => Value::I16(!v),
732 Value::U32(v) => Value::U32(!v),
733 Value::V32(v) => Value::V32(!v),
734 Value::I32(v) => Value::I32(!v),
735 Value::Z32(v) => Value::Z32(!v),
736 Value::U64(v) => Value::U64(!v),
737 Value::V64(v) => Value::V64(!v),
738 Value::I64(v) => Value::I64(!v),
739 Value::Z64(v) => Value::Z64(!v),
740 Value::F32(_) => Value::error(literal!("can't apply not to F32")),
741 Value::F64(_) => Value::error(literal!("can't apply not to F64")),
742 Value::Decimal(_) => Value::error(literal!("can't apply not to Decimal")),
743 Value::DateTime(_) => Value::error(literal!("can't apply not to DateTime")),
744 Value::Duration(_) => Value::error(literal!("can't apply not to Duration")),
745 Value::String(_) => Value::error(literal!("can't apply not to String")),
746 Value::Bytes(_) => Value::error(literal!("can't apply not to Bytes")),
747 Value::Error(_) => Value::error(literal!("can't apply not to Error")),
748 Value::Map(_) => Value::error(literal!("can't apply not to Map")),
749 Value::Abstract(_) => Value::error(literal!("can't apply not to Abstract")),
750 Value::Array(elts) => {
751 Value::Array(ValArray::from_iter_exact(elts.iter().cloned().map(|v| !v)))
752 }
753 }
754 }
755}