1use crate::{
2 Context, JsBigInt, JsResult, JsValue, JsVariant,
3 builtins::{
4 Number,
5 math::Math,
6 number::{f64_to_int32, f64_to_uint32},
7 },
8 error::JsNativeError,
9 js_string,
10 value::{JsSymbol, Numeric, PreferredType},
11};
12
13impl JsValue {
14 pub fn add(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
16 Ok(match (self.variant(), other.variant()) {
17 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
20 .checked_add(y)
21 .map_or_else(|| Self::new(f64::from(x) + f64::from(y)), Self::new),
22 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x + y),
23 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) + y),
24 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x + f64::from(y)),
25 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::add(&x, &y)),
26
27 (JsVariant::String(x), JsVariant::String(y)) => Self::from(js_string!(&x, &y)),
29
30 (_, _) => {
32 let x = self.to_primitive(context, PreferredType::Default)?;
33 let y = other.to_primitive(context, PreferredType::Default)?;
34 match (x.variant(), y.variant()) {
35 (JsVariant::String(x), _) => Self::from(js_string!(&x, &y.to_string(context)?)),
36 (_, JsVariant::String(y)) => Self::from(js_string!(&x.to_string(context)?, &y)),
37 (_, _) => {
38 match (x.to_numeric(context)?, y.to_numeric(context)?) {
39 (Numeric::Number(x), Numeric::Number(y)) => Self::new(x + y),
40 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
41 Self::new(JsBigInt::add(x, y))
42 }
43 (_, _) => return Err(JsNativeError::typ()
44 .with_message(
45 "cannot mix BigInt and other types, use explicit conversions",
46 )
47 .into()),
48 }
49 }
50 }
51 }
52 })
53 }
54
55 pub fn sub(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
57 Ok(match (self.variant(), other.variant()) {
58 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
60 .checked_sub(y)
61 .map_or_else(|| Self::new(f64::from(x) - f64::from(y)), Self::new),
62 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x - y),
63 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) - y),
64 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x - f64::from(y)),
65
66 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::sub(&x, &y)),
67
68 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
70 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a - b),
71 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::sub(x, y)),
72 (_, _) => {
73 return Err(JsNativeError::typ()
74 .with_message("cannot mix BigInt and other types, use explicit conversions")
75 .into());
76 }
77 },
78 })
79 }
80
81 pub fn mul(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
83 Ok(match (self.variant(), other.variant()) {
84 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
86 .checked_mul(y)
87 .filter(|v| *v != 0 || i32::min(x, y) >= 0)
89 .map_or_else(|| Self::new(f64::from(x) * f64::from(y)), Self::new),
90 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x * y),
91 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) * y),
92 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x * f64::from(y)),
93
94 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::mul(&x, &y)),
95
96 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
98 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a * b),
99 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::mul(x, y)),
100 (_, _) => {
101 return Err(JsNativeError::typ()
102 .with_message("cannot mix BigInt and other types, use explicit conversions")
103 .into());
104 }
105 },
106 })
107 }
108
109 pub fn div(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
111 Ok(match (self.variant(), other.variant()) {
112 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
114 .checked_div(y)
115 .filter(|div| y * div == x)
116 .map_or_else(|| Self::new(f64::from(x) / f64::from(y)), Self::new),
117 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x / y),
118 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) / y),
119 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x / f64::from(y)),
120
121 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => {
122 if y.is_zero() {
123 return Err(JsNativeError::range()
124 .with_message("BigInt division by zero")
125 .into());
126 }
127 Self::new(JsBigInt::div(&x, &y))
128 }
129
130 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
132 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a / b),
133 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
134 if y.is_zero() {
135 return Err(JsNativeError::range()
136 .with_message("BigInt division by zero")
137 .into());
138 }
139 Self::new(JsBigInt::div(x, y))
140 }
141 (_, _) => {
142 return Err(JsNativeError::typ()
143 .with_message("cannot mix BigInt and other types, use explicit conversions")
144 .into());
145 }
146 },
147 })
148 }
149
150 pub fn rem(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
152 Ok(match (self.variant(), other.variant()) {
153 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
155 if y == 0 {
156 Self::nan()
157 } else {
158 match x % y {
159 rem if rem == 0 && x < 0 => Self::new(-0.0),
160 rem => Self::new(rem),
161 }
162 }
163 }
164 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new((x % y).copysign(x)),
165 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
166 let x = f64::from(x);
167 Self::new((x % y).copysign(x))
168 }
169
170 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
171 Self::new((x % f64::from(y)).copysign(x))
172 }
173
174 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => {
175 if y.is_zero() {
176 return Err(JsNativeError::range()
177 .with_message("BigInt division by zero")
178 .into());
179 }
180 Self::new(JsBigInt::rem(&x, &y))
181 }
182
183 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
185 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a % b),
186 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
187 if y.is_zero() {
188 return Err(JsNativeError::range()
189 .with_message("BigInt division by zero")
190 .into());
191 }
192 Self::new(JsBigInt::rem(x, y))
193 }
194 (_, _) => {
195 return Err(JsNativeError::typ()
196 .with_message("cannot mix BigInt and other types, use explicit conversions")
197 .into());
198 }
199 },
200 })
201 }
202
203 #[allow(clippy::float_cmp)]
206 pub fn pow(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
207 Ok(match (self.variant(), other.variant()) {
208 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => u32::try_from(y)
210 .ok()
211 .and_then(|y| x.checked_pow(y))
212 .map_or_else(
213 || Self::new(Math::exponentiate(f64::from(x), f64::from(y))),
214 Self::new,
215 ),
216 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(Math::exponentiate(x, y)),
217 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
218 Self::new(Math::exponentiate(f64::from(x), y))
219 }
220 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
221 Self::new(Math::exponentiate(x, f64::from(y)))
222 }
223 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => Self::new(JsBigInt::pow(&a, &b)?),
224
225 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
227 (Numeric::Number(a), Numeric::Number(b)) => Self::new(Math::exponentiate(a, b)),
228 (Numeric::BigInt(ref a), Numeric::BigInt(ref b)) => Self::new(JsBigInt::pow(a, b)?),
229 (_, _) => {
230 return Err(JsNativeError::typ()
231 .with_message("cannot mix BigInt and other types, use explicit conversions")
232 .into());
233 }
234 },
235 })
236 }
237
238 pub fn bitand(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
240 Ok(match (self.variant(), other.variant()) {
241 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x & y),
243 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
244 Self::new(f64_to_int32(x) & f64_to_int32(y))
245 }
246 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x & f64_to_int32(y)),
247 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) & y),
248
249 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitand(&x, &y)),
250
251 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
253 (Numeric::Number(a), Numeric::Number(b)) => {
254 Self::new(f64_to_int32(a) & f64_to_int32(b))
255 }
256 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
257 Self::new(JsBigInt::bitand(x, y))
258 }
259 (_, _) => {
260 return Err(JsNativeError::typ()
261 .with_message("cannot mix BigInt and other types, use explicit conversions")
262 .into());
263 }
264 },
265 })
266 }
267
268 pub fn bitor(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
270 Ok(match (self.variant(), other.variant()) {
271 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x | y),
273 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
274 Self::new(f64_to_int32(x) | f64_to_int32(y))
275 }
276 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x | f64_to_int32(y)),
277 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) | y),
278
279 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitor(&x, &y)),
280
281 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
283 (Numeric::Number(a), Numeric::Number(b)) => {
284 Self::new(f64_to_int32(a) | f64_to_int32(b))
285 }
286 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
287 Self::new(JsBigInt::bitor(x, y))
288 }
289 (_, _) => {
290 return Err(JsNativeError::typ()
291 .with_message("cannot mix BigInt and other types, use explicit conversions")
292 .into());
293 }
294 },
295 })
296 }
297
298 pub fn bitxor(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
300 Ok(match (self.variant(), other.variant()) {
301 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x ^ y),
303 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
304 Self::new(f64_to_int32(x) ^ f64_to_int32(y))
305 }
306 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x ^ f64_to_int32(y)),
307 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) ^ y),
308
309 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitxor(&x, &y)),
310
311 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
313 (Numeric::Number(a), Numeric::Number(b)) => {
314 Self::new(f64_to_int32(a) ^ f64_to_int32(b))
315 }
316 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
317 Self::new(JsBigInt::bitxor(x, y))
318 }
319 (_, _) => {
320 return Err(JsNativeError::typ()
321 .with_message("cannot mix BigInt and other types, use explicit conversions")
322 .into());
323 }
324 },
325 })
326 }
327
328 pub fn shl(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
330 Ok(match (self.variant(), other.variant()) {
331 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
333 Self::new(x.wrapping_shl(y as u32))
334 }
335 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
336 Self::new(f64_to_int32(x).wrapping_shl(f64_to_uint32(y)))
337 }
338 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
339 Self::new(x.wrapping_shl(f64_to_uint32(y)))
340 }
341 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
342 Self::new(f64_to_int32(x).wrapping_shl(y as u32))
343 }
344
345 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => {
346 Self::new(JsBigInt::shift_left(&a, &b)?)
347 }
348
349 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
351 (Numeric::Number(x), Numeric::Number(y)) => {
352 Self::new(f64_to_int32(x).wrapping_shl(f64_to_uint32(y)))
353 }
354 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
355 Self::new(JsBigInt::shift_left(x, y)?)
356 }
357 (_, _) => {
358 return Err(JsNativeError::typ()
359 .with_message("cannot mix BigInt and other types, use explicit conversions")
360 .into());
361 }
362 },
363 })
364 }
365
366 pub fn shr(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
368 Ok(match (self.variant(), other.variant()) {
369 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
371 Self::new(x.wrapping_shr(y as u32))
372 }
373 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
374 Self::new(f64_to_int32(x).wrapping_shr(f64_to_uint32(y)))
375 }
376 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
377 Self::new(x.wrapping_shr(f64_to_uint32(y)))
378 }
379 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
380 Self::new(f64_to_int32(x).wrapping_shr(y as u32))
381 }
382
383 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => {
384 Self::new(JsBigInt::shift_right(&a, &b)?)
385 }
386
387 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
389 (Numeric::Number(x), Numeric::Number(y)) => {
390 Self::new(f64_to_int32(x).wrapping_shr(f64_to_uint32(y)))
391 }
392 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
393 Self::new(JsBigInt::shift_right(x, y)?)
394 }
395 (_, _) => {
396 return Err(JsNativeError::typ()
397 .with_message("cannot mix BigInt and other types, use explicit conversions")
398 .into());
399 }
400 },
401 })
402 }
403
404 pub fn ushr(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
406 Ok(match (self.variant(), other.variant()) {
407 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
409 Self::new((x as u32).wrapping_shr(y as u32))
410 }
411 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
412 Self::new(f64_to_uint32(x).wrapping_shr(f64_to_uint32(y)))
413 }
414 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
415 Self::new((x as u32).wrapping_shr(f64_to_uint32(y)))
416 }
417 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
418 Self::new(f64_to_uint32(x).wrapping_shr(y as u32))
419 }
420
421 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
423 (Numeric::Number(x), Numeric::Number(y)) => {
424 Self::new(f64_to_uint32(x).wrapping_shr(f64_to_uint32(y)))
425 }
426 (Numeric::BigInt(_), Numeric::BigInt(_)) => {
427 return Err(JsNativeError::typ()
428 .with_message("BigInts have no unsigned right shift, use >> instead")
429 .into());
430 }
431 (_, _) => {
432 return Err(JsNativeError::typ()
433 .with_message("cannot mix BigInt and other types, use explicit conversions")
434 .into());
435 }
436 },
437 })
438 }
439
440 pub fn instance_of(&self, target: &Self, context: &mut Context) -> JsResult<bool> {
447 if !target.is_object() {
449 return Err(JsNativeError::typ()
450 .with_message(format!(
451 "right-hand side of 'instanceof' should be an object, got `{}`",
452 target.type_of()
453 ))
454 .into());
455 }
456
457 match target.get_method(JsSymbol::has_instance(), context)? {
459 Some(instance_of_handler) => {
461 Ok(instance_of_handler
463 .call(target, std::slice::from_ref(self), context)?
464 .to_boolean())
465 }
466 None if target.is_callable() => {
467 Self::ordinary_has_instance(target, self, context)
469 }
470 None => {
471 Err(JsNativeError::typ()
473 .with_message("right-hand side of 'instanceof' is not callable")
474 .into())
475 }
476 }
477 }
478
479 pub fn neg(&self, context: &mut Context) -> JsResult<Self> {
481 Ok(match self.variant() {
482 JsVariant::Symbol(_) | JsVariant::Undefined => Self::new(f64::NAN),
483 JsVariant::Object(_) => Self::new(
484 self.to_numeric_number(context)
485 .map_or(f64::NAN, std::ops::Neg::neg),
486 ),
487 JsVariant::String(str) => Self::new(-str.to_number()),
488 JsVariant::Float64(num) => Self::new(-num),
489 JsVariant::Integer32(0) | JsVariant::Boolean(false) | JsVariant::Null => {
490 Self::new(-0.0)
491 }
492 JsVariant::Integer32(num) => Self::new(-num),
493 JsVariant::Boolean(true) => Self::new(-1),
494 JsVariant::BigInt(x) => Self::new(JsBigInt::neg(&x)),
495 })
496 }
497
498 #[inline]
500 pub fn not(&self) -> JsResult<bool> {
501 Ok(!self.to_boolean())
502 }
503
504 pub fn abstract_relation(
522 &self,
523 other: &Self,
524 left_first: bool,
525 context: &mut Context,
526 ) -> JsResult<AbstractRelation> {
527 Ok(match (self.variant(), other.variant()) {
528 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => (x < y).into(),
530 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Number::less_than(f64::from(x), y),
531 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Number::less_than(x, f64::from(y)),
532 (JsVariant::Float64(x), JsVariant::Float64(y)) => Number::less_than(x, y),
533 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => (x < y).into(),
534
535 (_, _) => {
537 let (px, py) = if left_first {
538 let px = self.to_primitive(context, PreferredType::Number)?;
539 let py = other.to_primitive(context, PreferredType::Number)?;
540 (px, py)
541 } else {
542 let py = other.to_primitive(context, PreferredType::Number)?;
544 let px = self.to_primitive(context, PreferredType::Number)?;
545 (px, py)
546 };
547
548 match (px.variant(), py.variant()) {
549 (JsVariant::String(x), JsVariant::String(y)) => (x < y).into(),
550 (JsVariant::BigInt(x), JsVariant::String(y)) => JsBigInt::from_js_string(&y)
551 .map_or(AbstractRelation::Undefined, |y| (x < y).into()),
552 (JsVariant::String(x), JsVariant::BigInt(y)) => JsBigInt::from_js_string(&x)
553 .map_or(AbstractRelation::Undefined, |x| (x < y).into()),
554 (_, _) => match (px.to_numeric(context)?, py.to_numeric(context)?) {
555 (Numeric::Number(x), Numeric::Number(y)) => Number::less_than(x, y),
556 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => (x < y).into(),
557 (Numeric::BigInt(ref x), Numeric::Number(y)) => {
558 if y.is_nan() {
559 return Ok(AbstractRelation::Undefined);
560 }
561 if y.is_infinite() {
562 return Ok(y.is_sign_positive().into());
563 }
564
565 if let Ok(y) = JsBigInt::try_from(y) {
566 return Ok((x < &y).into());
567 }
568
569 (x.to_f64() < y).into()
570 }
571 (Numeric::Number(x), Numeric::BigInt(ref y)) => {
572 if x.is_nan() {
573 return Ok(AbstractRelation::Undefined);
574 }
575 if x.is_infinite() {
576 return Ok(x.is_sign_negative().into());
577 }
578
579 if let Ok(x) = JsBigInt::try_from(x) {
580 return Ok((&x < y).into());
581 }
582
583 (x < y.to_f64()).into()
584 }
585 },
586 }
587 }
588 })
589 }
590
591 #[inline]
601 pub fn lt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
602 match self.abstract_relation(other, true, context)? {
603 AbstractRelation::True => Ok(true),
604 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
605 }
606 }
607
608 #[inline]
618 pub fn le(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
619 match other.abstract_relation(self, false, context)? {
620 AbstractRelation::False => Ok(true),
621 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
622 }
623 }
624
625 #[inline]
635 pub fn gt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
636 match other.abstract_relation(self, false, context)? {
637 AbstractRelation::True => Ok(true),
638 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
639 }
640 }
641
642 #[inline]
652 pub fn ge(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
653 match self.abstract_relation(other, true, context)? {
654 AbstractRelation::False => Ok(true),
655 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
656 }
657 }
658
659 #[inline]
672 fn as_number_cheap(&self) -> Option<f64> {
673 if let Some(i) = self.0.as_integer32() {
674 Some(f64::from(i))
675 } else {
676 self.0.as_float64()
677 }
678 }
679
680 #[inline]
682 #[allow(clippy::float_cmp)]
683 pub(crate) fn add_fast(&self, other: &Self) -> Option<Self> {
684 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
685 return Some(
686 x.checked_add(y)
687 .map_or_else(|| Self::new(f64::from(x) + f64::from(y)), Self::new),
688 );
689 }
690 let x = self.as_number_cheap()?;
691 let y = other.as_number_cheap()?;
692 Some(Self::new(x + y))
693 }
694
695 #[inline]
697 pub(crate) fn sub_fast(&self, other: &Self) -> Option<Self> {
698 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
699 return Some(
700 x.checked_sub(y)
701 .map_or_else(|| Self::new(f64::from(x) - f64::from(y)), Self::new),
702 );
703 }
704 let x = self.as_number_cheap()?;
705 let y = other.as_number_cheap()?;
706 Some(Self::new(x - y))
707 }
708
709 #[inline]
711 pub(crate) fn mul_fast(&self, other: &Self) -> Option<Self> {
712 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
713 return Some(
714 x.checked_mul(y)
715 .filter(|v| *v != 0 || i32::min(x, y) >= 0)
716 .map_or_else(|| Self::new(f64::from(x) * f64::from(y)), Self::new),
717 );
718 }
719 let x = self.as_number_cheap()?;
720 let y = other.as_number_cheap()?;
721 Some(Self::new(x * y))
722 }
723
724 #[inline]
726 #[allow(clippy::float_cmp)]
727 pub(crate) fn div_fast(&self, other: &Self) -> Option<Self> {
728 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
729 return Some(
730 x.checked_div(y)
731 .filter(|div| y * div == x)
732 .map_or_else(|| Self::new(f64::from(x) / f64::from(y)), Self::new),
733 );
734 }
735 let x = self.as_number_cheap()?;
736 let y = other.as_number_cheap()?;
737 Some(Self::new(x / y))
738 }
739
740 #[inline]
742 pub(crate) fn rem_fast(&self, other: &Self) -> Option<Self> {
743 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
744 if y == 0 {
745 return Some(Self::nan());
746 }
747 return Some(match x % y {
748 rem if rem == 0 && x < 0 => Self::new(-0.0),
749 rem => Self::new(rem),
750 });
751 }
752 let x = self.as_number_cheap()?;
753 let y = other.as_number_cheap()?;
754 Some(Self::new((x % y).copysign(x)))
755 }
756
757 #[inline]
759 #[allow(clippy::float_cmp)]
760 pub(crate) fn pow_fast(&self, other: &Self) -> Option<Self> {
761 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
762 return Some(
763 u32::try_from(y)
764 .ok()
765 .and_then(|y| x.checked_pow(y))
766 .map_or_else(
767 || Self::new(Math::exponentiate(f64::from(x), f64::from(y))),
768 Self::new,
769 ),
770 );
771 }
772 let x = self.as_number_cheap()?;
773 let y = other.as_number_cheap()?;
774 Some(Self::new(Math::exponentiate(x, y)))
775 }
776
777 #[inline]
779 pub(crate) fn bitand_fast(&self, other: &Self) -> Option<Self> {
780 let x = self.0.as_integer32()?;
781 let y = other.0.as_integer32()?;
782 Some(Self::new(x & y))
783 }
784
785 #[inline]
787 pub(crate) fn bitor_fast(&self, other: &Self) -> Option<Self> {
788 let x = self.0.as_integer32()?;
789 let y = other.0.as_integer32()?;
790 Some(Self::new(x | y))
791 }
792
793 #[inline]
795 pub(crate) fn bitxor_fast(&self, other: &Self) -> Option<Self> {
796 let x = self.0.as_integer32()?;
797 let y = other.0.as_integer32()?;
798 Some(Self::new(x ^ y))
799 }
800
801 #[inline]
803 pub(crate) fn shl_fast(&self, other: &Self) -> Option<Self> {
804 let x = self.0.as_integer32()?;
805 let y = other.0.as_integer32()?;
806 Some(Self::new(x.wrapping_shl(y as u32)))
807 }
808
809 #[inline]
811 pub(crate) fn shr_fast(&self, other: &Self) -> Option<Self> {
812 let x = self.0.as_integer32()?;
813 let y = other.0.as_integer32()?;
814 Some(Self::new(x.wrapping_shr(y as u32)))
815 }
816
817 #[inline]
819 pub(crate) fn ushr_fast(&self, other: &Self) -> Option<Self> {
820 let x = self.0.as_integer32()?;
821 let y = other.0.as_integer32()?;
822 Some(Self::new((x as u32).wrapping_shr(y as u32)))
823 }
824
825 #[inline]
827 pub(crate) fn lt_fast(&self, other: &Self) -> Option<bool> {
828 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
829 return Some(x < y);
830 }
831 let x = self.as_number_cheap()?;
832 let y = other.as_number_cheap()?;
833 Some(x < y)
834 }
835
836 #[inline]
838 pub(crate) fn le_fast(&self, other: &Self) -> Option<bool> {
839 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
840 return Some(x <= y);
841 }
842 let x = self.as_number_cheap()?;
843 let y = other.as_number_cheap()?;
844 Some(x <= y)
845 }
846
847 #[inline]
849 pub(crate) fn gt_fast(&self, other: &Self) -> Option<bool> {
850 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
851 return Some(x > y);
852 }
853 let x = self.as_number_cheap()?;
854 let y = other.as_number_cheap()?;
855 Some(x > y)
856 }
857
858 #[inline]
860 pub(crate) fn ge_fast(&self, other: &Self) -> Option<bool> {
861 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
862 return Some(x >= y);
863 }
864 let x = self.as_number_cheap()?;
865 let y = other.as_number_cheap()?;
866 Some(x >= y)
867 }
868
869 #[inline]
871 #[allow(clippy::float_cmp)]
872 pub(crate) fn equals_fast(&self, other: &Self) -> Option<Self> {
873 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
874 return Some(Self::new(x == y));
875 }
876 let x = self.as_number_cheap()?;
877 let y = other.as_number_cheap()?;
878 Some(Self::new(x == y))
879 }
880
881 #[inline]
883 #[allow(clippy::float_cmp)]
884 pub(crate) fn not_equals_fast(&self, other: &Self) -> Option<Self> {
885 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
886 return Some(Self::new(x != y));
887 }
888 let x = self.as_number_cheap()?;
889 let y = other.as_number_cheap()?;
890 Some(Self::new(x != y))
891 }
892}
893
894#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
902pub enum AbstractRelation {
903 True,
905 False,
907 Undefined,
909}
910
911impl From<bool> for AbstractRelation {
912 #[inline]
913 fn from(value: bool) -> Self {
914 if value { Self::True } else { Self::False }
915 }
916}