1use crate::{
2 Context, JsBigInt, JsResult, JsValue, JsVariant,
3 builtins::{
4 Number,
5 number::{f64_to_int32, f64_to_uint32},
6 },
7 error::JsNativeError,
8 js_string,
9 value::{JsSymbol, Numeric, PreferredType},
10};
11
12impl JsValue {
13 pub fn add(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
15 Ok(match (self.variant(), other.variant()) {
16 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
19 .checked_add(y)
20 .map_or_else(|| Self::new(f64::from(x) + f64::from(y)), Self::new),
21 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x + y),
22 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) + y),
23 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x + f64::from(y)),
24 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::add(&x, &y)),
25
26 (JsVariant::String(x), JsVariant::String(y)) => Self::from(js_string!(&x, &y)),
28
29 (_, _) => {
31 let x = self.to_primitive(context, PreferredType::Default)?;
32 let y = other.to_primitive(context, PreferredType::Default)?;
33 match (x.variant(), y.variant()) {
34 (JsVariant::String(x), _) => Self::from(js_string!(&x, &y.to_string(context)?)),
35 (_, JsVariant::String(y)) => Self::from(js_string!(&x.to_string(context)?, &y)),
36 (_, _) => {
37 match (x.to_numeric(context)?, y.to_numeric(context)?) {
38 (Numeric::Number(x), Numeric::Number(y)) => Self::new(x + y),
39 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
40 Self::new(JsBigInt::add(x, y))
41 }
42 (_, _) => return Err(JsNativeError::typ()
43 .with_message(
44 "cannot mix BigInt and other types, use explicit conversions",
45 )
46 .into()),
47 }
48 }
49 }
50 }
51 })
52 }
53
54 pub fn sub(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
56 Ok(match (self.variant(), other.variant()) {
57 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
59 .checked_sub(y)
60 .map_or_else(|| Self::new(f64::from(x) - f64::from(y)), Self::new),
61 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x - y),
62 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) - y),
63 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x - f64::from(y)),
64
65 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::sub(&x, &y)),
66
67 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
69 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a - b),
70 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::sub(x, y)),
71 (_, _) => {
72 return Err(JsNativeError::typ()
73 .with_message("cannot mix BigInt and other types, use explicit conversions")
74 .into());
75 }
76 },
77 })
78 }
79
80 pub fn mul(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
82 Ok(match (self.variant(), other.variant()) {
83 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
85 .checked_mul(y)
86 .filter(|v| *v != 0 || i32::min(x, y) >= 0)
88 .map_or_else(|| Self::new(f64::from(x) * f64::from(y)), Self::new),
89 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x * y),
90 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) * y),
91 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x * f64::from(y)),
92
93 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::mul(&x, &y)),
94
95 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
97 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a * b),
98 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::mul(x, y)),
99 (_, _) => {
100 return Err(JsNativeError::typ()
101 .with_message("cannot mix BigInt and other types, use explicit conversions")
102 .into());
103 }
104 },
105 })
106 }
107
108 pub fn div(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
110 Ok(match (self.variant(), other.variant()) {
111 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => x
113 .checked_div(y)
114 .filter(|div| y * div == x)
115 .map_or_else(|| Self::new(f64::from(x) / f64::from(y)), Self::new),
116 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new(x / y),
117 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(f64::from(x) / y),
118 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x / f64::from(y)),
119
120 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => {
121 if y.is_zero() {
122 return Err(JsNativeError::range()
123 .with_message("BigInt division by zero")
124 .into());
125 }
126 Self::new(JsBigInt::div(&x, &y))
127 }
128
129 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
131 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a / b),
132 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
133 if y.is_zero() {
134 return Err(JsNativeError::range()
135 .with_message("BigInt division by zero")
136 .into());
137 }
138 Self::new(JsBigInt::div(x, y))
139 }
140 (_, _) => {
141 return Err(JsNativeError::typ()
142 .with_message("cannot mix BigInt and other types, use explicit conversions")
143 .into());
144 }
145 },
146 })
147 }
148
149 pub fn rem(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
151 Ok(match (self.variant(), other.variant()) {
152 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
154 if y == 0 {
155 Self::nan()
156 } else {
157 match x % y {
158 rem if rem == 0 && x < 0 => Self::new(-0.0),
159 rem => Self::new(rem),
160 }
161 }
162 }
163 (JsVariant::Float64(x), JsVariant::Float64(y)) => Self::new((x % y).copysign(x)),
164 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
165 let x = f64::from(x);
166 Self::new((x % y).copysign(x))
167 }
168
169 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
170 Self::new((x % f64::from(y)).copysign(x))
171 }
172
173 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => {
174 if y.is_zero() {
175 return Err(JsNativeError::range()
176 .with_message("BigInt division by zero")
177 .into());
178 }
179 Self::new(JsBigInt::rem(&x, &y))
180 }
181
182 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
184 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a % b),
185 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
186 if y.is_zero() {
187 return Err(JsNativeError::range()
188 .with_message("BigInt division by zero")
189 .into());
190 }
191 Self::new(JsBigInt::rem(x, y))
192 }
193 (_, _) => {
194 return Err(JsNativeError::typ()
195 .with_message("cannot mix BigInt and other types, use explicit conversions")
196 .into());
197 }
198 },
199 })
200 }
201
202 #[allow(clippy::float_cmp)]
205 pub fn pow(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
206 Ok(match (self.variant(), other.variant()) {
207 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => u32::try_from(y)
209 .ok()
210 .and_then(|y| x.checked_pow(y))
211 .map_or_else(|| Self::new(f64::from(x).powi(y)), Self::new),
212 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
213 if x.abs() == 1.0 && y.is_infinite() {
214 Self::nan()
215 } else {
216 Self::new(x.powf(y))
217 }
218 }
219 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
220 if x.wrapping_abs() == 1 && y.is_infinite() {
221 Self::nan()
222 } else {
223 Self::new(f64::from(x).powf(y))
224 }
225 }
226 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(x.powi(y)),
227 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => Self::new(JsBigInt::pow(&a, &b)?),
228
229 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
231 (Numeric::Number(a), Numeric::Number(b)) => {
232 if a.abs() == 1.0 && b.is_infinite() {
233 Self::nan()
234 } else {
235 Self::new(a.powf(b))
236 }
237 }
238 (Numeric::BigInt(ref a), Numeric::BigInt(ref b)) => Self::new(JsBigInt::pow(a, b)?),
239 (_, _) => {
240 return Err(JsNativeError::typ()
241 .with_message("cannot mix BigInt and other types, use explicit conversions")
242 .into());
243 }
244 },
245 })
246 }
247
248 pub fn bitand(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
250 Ok(match (self.variant(), other.variant()) {
251 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x & y),
253 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
254 Self::new(f64_to_int32(x) & f64_to_int32(y))
255 }
256 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x & f64_to_int32(y)),
257 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) & y),
258
259 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitand(&x, &y)),
260
261 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
263 (Numeric::Number(a), Numeric::Number(b)) => {
264 Self::new(f64_to_int32(a) & f64_to_int32(b))
265 }
266 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
267 Self::new(JsBigInt::bitand(x, y))
268 }
269 (_, _) => {
270 return Err(JsNativeError::typ()
271 .with_message("cannot mix BigInt and other types, use explicit conversions")
272 .into());
273 }
274 },
275 })
276 }
277
278 pub fn bitor(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
280 Ok(match (self.variant(), other.variant()) {
281 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x | y),
283 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
284 Self::new(f64_to_int32(x) | f64_to_int32(y))
285 }
286 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x | f64_to_int32(y)),
287 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) | y),
288
289 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitor(&x, &y)),
290
291 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
293 (Numeric::Number(a), Numeric::Number(b)) => {
294 Self::new(f64_to_int32(a) | f64_to_int32(b))
295 }
296 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
297 Self::new(JsBigInt::bitor(x, y))
298 }
299 (_, _) => {
300 return Err(JsNativeError::typ()
301 .with_message("cannot mix BigInt and other types, use explicit conversions")
302 .into());
303 }
304 },
305 })
306 }
307
308 pub fn bitxor(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
310 Ok(match (self.variant(), other.variant()) {
311 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => Self::new(x ^ y),
313 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
314 Self::new(f64_to_int32(x) ^ f64_to_int32(y))
315 }
316 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Self::new(x ^ f64_to_int32(y)),
317 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Self::new(f64_to_int32(x) ^ y),
318
319 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => Self::new(JsBigInt::bitxor(&x, &y)),
320
321 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
323 (Numeric::Number(a), Numeric::Number(b)) => {
324 Self::new(f64_to_int32(a) ^ f64_to_int32(b))
325 }
326 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
327 Self::new(JsBigInt::bitxor(x, y))
328 }
329 (_, _) => {
330 return Err(JsNativeError::typ()
331 .with_message("cannot mix BigInt and other types, use explicit conversions")
332 .into());
333 }
334 },
335 })
336 }
337
338 pub fn shl(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
340 Ok(match (self.variant(), other.variant()) {
341 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
343 Self::new(x.wrapping_shl(y as u32))
344 }
345 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
346 Self::new(f64_to_int32(x).wrapping_shl(f64_to_uint32(y)))
347 }
348 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
349 Self::new(x.wrapping_shl(f64_to_uint32(y)))
350 }
351 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
352 Self::new(f64_to_int32(x).wrapping_shl(y as u32))
353 }
354
355 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => {
356 Self::new(JsBigInt::shift_left(&a, &b)?)
357 }
358
359 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
361 (Numeric::Number(x), Numeric::Number(y)) => {
362 Self::new(f64_to_int32(x).wrapping_shl(f64_to_uint32(y)))
363 }
364 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
365 Self::new(JsBigInt::shift_left(x, y)?)
366 }
367 (_, _) => {
368 return Err(JsNativeError::typ()
369 .with_message("cannot mix BigInt and other types, use explicit conversions")
370 .into());
371 }
372 },
373 })
374 }
375
376 pub fn shr(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
378 Ok(match (self.variant(), other.variant()) {
379 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
381 Self::new(x.wrapping_shr(y as u32))
382 }
383 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
384 Self::new(f64_to_int32(x).wrapping_shr(f64_to_uint32(y)))
385 }
386 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
387 Self::new(x.wrapping_shr(f64_to_uint32(y)))
388 }
389 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
390 Self::new(f64_to_int32(x).wrapping_shr(y as u32))
391 }
392
393 (JsVariant::BigInt(a), JsVariant::BigInt(b)) => {
394 Self::new(JsBigInt::shift_right(&a, &b)?)
395 }
396
397 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
399 (Numeric::Number(x), Numeric::Number(y)) => {
400 Self::new(f64_to_int32(x).wrapping_shr(f64_to_uint32(y)))
401 }
402 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
403 Self::new(JsBigInt::shift_right(x, y)?)
404 }
405 (_, _) => {
406 return Err(JsNativeError::typ()
407 .with_message("cannot mix BigInt and other types, use explicit conversions")
408 .into());
409 }
410 },
411 })
412 }
413
414 pub fn ushr(&self, other: &Self, context: &mut Context) -> JsResult<Self> {
416 Ok(match (self.variant(), other.variant()) {
417 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => {
419 Self::new((x as u32).wrapping_shr(y as u32))
420 }
421 (JsVariant::Float64(x), JsVariant::Float64(y)) => {
422 Self::new(f64_to_uint32(x).wrapping_shr(f64_to_uint32(y)))
423 }
424 (JsVariant::Integer32(x), JsVariant::Float64(y)) => {
425 Self::new((x as u32).wrapping_shr(f64_to_uint32(y)))
426 }
427 (JsVariant::Float64(x), JsVariant::Integer32(y)) => {
428 Self::new(f64_to_uint32(x).wrapping_shr(y as u32))
429 }
430
431 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
433 (Numeric::Number(x), Numeric::Number(y)) => {
434 Self::new(f64_to_uint32(x).wrapping_shr(f64_to_uint32(y)))
435 }
436 (Numeric::BigInt(_), Numeric::BigInt(_)) => {
437 return Err(JsNativeError::typ()
438 .with_message("BigInts have no unsigned right shift, use >> instead")
439 .into());
440 }
441 (_, _) => {
442 return Err(JsNativeError::typ()
443 .with_message("cannot mix BigInt and other types, use explicit conversions")
444 .into());
445 }
446 },
447 })
448 }
449
450 pub fn instance_of(&self, target: &Self, context: &mut Context) -> JsResult<bool> {
457 if !target.is_object() {
459 return Err(JsNativeError::typ()
460 .with_message(format!(
461 "right-hand side of 'instanceof' should be an object, got `{}`",
462 target.type_of()
463 ))
464 .into());
465 }
466
467 match target.get_method(JsSymbol::has_instance(), context)? {
469 Some(instance_of_handler) => {
471 Ok(instance_of_handler
473 .call(target, std::slice::from_ref(self), context)?
474 .to_boolean())
475 }
476 None if target.is_callable() => {
477 Self::ordinary_has_instance(target, self, context)
479 }
480 None => {
481 Err(JsNativeError::typ()
483 .with_message("right-hand side of 'instanceof' is not callable")
484 .into())
485 }
486 }
487 }
488
489 pub fn neg(&self, context: &mut Context) -> JsResult<Self> {
491 Ok(match self.variant() {
492 JsVariant::Symbol(_) | JsVariant::Undefined => Self::new(f64::NAN),
493 JsVariant::Object(_) => Self::new(
494 self.to_numeric_number(context)
495 .map_or(f64::NAN, std::ops::Neg::neg),
496 ),
497 JsVariant::String(str) => Self::new(-str.to_number()),
498 JsVariant::Float64(num) => Self::new(-num),
499 JsVariant::Integer32(0) | JsVariant::Boolean(false) | JsVariant::Null => {
500 Self::new(-0.0)
501 }
502 JsVariant::Integer32(num) => Self::new(-num),
503 JsVariant::Boolean(true) => Self::new(-1),
504 JsVariant::BigInt(x) => Self::new(JsBigInt::neg(&x)),
505 })
506 }
507
508 #[inline]
510 pub fn not(&self) -> JsResult<bool> {
511 Ok(!self.to_boolean())
512 }
513
514 pub fn abstract_relation(
532 &self,
533 other: &Self,
534 left_first: bool,
535 context: &mut Context,
536 ) -> JsResult<AbstractRelation> {
537 Ok(match (self.variant(), other.variant()) {
538 (JsVariant::Integer32(x), JsVariant::Integer32(y)) => (x < y).into(),
540 (JsVariant::Integer32(x), JsVariant::Float64(y)) => Number::less_than(f64::from(x), y),
541 (JsVariant::Float64(x), JsVariant::Integer32(y)) => Number::less_than(x, f64::from(y)),
542 (JsVariant::Float64(x), JsVariant::Float64(y)) => Number::less_than(x, y),
543 (JsVariant::BigInt(x), JsVariant::BigInt(y)) => (x < y).into(),
544
545 (_, _) => {
547 let (px, py) = if left_first {
548 let px = self.to_primitive(context, PreferredType::Number)?;
549 let py = other.to_primitive(context, PreferredType::Number)?;
550 (px, py)
551 } else {
552 let py = other.to_primitive(context, PreferredType::Number)?;
554 let px = self.to_primitive(context, PreferredType::Number)?;
555 (px, py)
556 };
557
558 match (px.variant(), py.variant()) {
559 (JsVariant::String(x), JsVariant::String(y)) => (x < y).into(),
560 (JsVariant::BigInt(x), JsVariant::String(y)) => JsBigInt::from_js_string(&y)
561 .map_or(AbstractRelation::Undefined, |y| (x < y).into()),
562 (JsVariant::String(x), JsVariant::BigInt(y)) => JsBigInt::from_js_string(&x)
563 .map_or(AbstractRelation::Undefined, |x| (x < y).into()),
564 (_, _) => match (px.to_numeric(context)?, py.to_numeric(context)?) {
565 (Numeric::Number(x), Numeric::Number(y)) => Number::less_than(x, y),
566 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => (x < y).into(),
567 (Numeric::BigInt(ref x), Numeric::Number(y)) => {
568 if y.is_nan() {
569 return Ok(AbstractRelation::Undefined);
570 }
571 if y.is_infinite() {
572 return Ok(y.is_sign_positive().into());
573 }
574
575 if let Ok(y) = JsBigInt::try_from(y) {
576 return Ok((x < &y).into());
577 }
578
579 (x.to_f64() < y).into()
580 }
581 (Numeric::Number(x), Numeric::BigInt(ref y)) => {
582 if x.is_nan() {
583 return Ok(AbstractRelation::Undefined);
584 }
585 if x.is_infinite() {
586 return Ok(x.is_sign_negative().into());
587 }
588
589 if let Ok(x) = JsBigInt::try_from(x) {
590 return Ok((&x < y).into());
591 }
592
593 (x < y.to_f64()).into()
594 }
595 },
596 }
597 }
598 })
599 }
600
601 #[inline]
611 pub fn lt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
612 match self.abstract_relation(other, true, context)? {
613 AbstractRelation::True => Ok(true),
614 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
615 }
616 }
617
618 #[inline]
628 pub fn le(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
629 match other.abstract_relation(self, false, context)? {
630 AbstractRelation::False => Ok(true),
631 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
632 }
633 }
634
635 #[inline]
645 pub fn gt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
646 match other.abstract_relation(self, false, context)? {
647 AbstractRelation::True => Ok(true),
648 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
649 }
650 }
651
652 #[inline]
662 pub fn ge(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
663 match self.abstract_relation(other, true, context)? {
664 AbstractRelation::False => Ok(true),
665 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
666 }
667 }
668
669 #[inline]
682 fn as_number_cheap(&self) -> Option<f64> {
683 if let Some(i) = self.0.as_integer32() {
684 Some(f64::from(i))
685 } else {
686 self.0.as_float64()
687 }
688 }
689
690 #[inline]
692 #[allow(clippy::float_cmp)]
693 pub(crate) fn add_fast(&self, other: &Self) -> Option<Self> {
694 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
695 return Some(
696 x.checked_add(y)
697 .map_or_else(|| Self::new(f64::from(x) + f64::from(y)), Self::new),
698 );
699 }
700 let x = self.as_number_cheap()?;
701 let y = other.as_number_cheap()?;
702 Some(Self::new(x + y))
703 }
704
705 #[inline]
707 pub(crate) fn sub_fast(&self, other: &Self) -> Option<Self> {
708 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
709 return Some(
710 x.checked_sub(y)
711 .map_or_else(|| Self::new(f64::from(x) - f64::from(y)), Self::new),
712 );
713 }
714 let x = self.as_number_cheap()?;
715 let y = other.as_number_cheap()?;
716 Some(Self::new(x - y))
717 }
718
719 #[inline]
721 pub(crate) fn mul_fast(&self, other: &Self) -> Option<Self> {
722 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
723 return Some(
724 x.checked_mul(y)
725 .filter(|v| *v != 0 || i32::min(x, y) >= 0)
726 .map_or_else(|| Self::new(f64::from(x) * f64::from(y)), Self::new),
727 );
728 }
729 let x = self.as_number_cheap()?;
730 let y = other.as_number_cheap()?;
731 Some(Self::new(x * y))
732 }
733
734 #[inline]
736 #[allow(clippy::float_cmp)]
737 pub(crate) fn div_fast(&self, other: &Self) -> Option<Self> {
738 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
739 return Some(
740 x.checked_div(y)
741 .filter(|div| y * div == x)
742 .map_or_else(|| Self::new(f64::from(x) / f64::from(y)), Self::new),
743 );
744 }
745 let x = self.as_number_cheap()?;
746 let y = other.as_number_cheap()?;
747 Some(Self::new(x / y))
748 }
749
750 #[inline]
752 pub(crate) fn rem_fast(&self, other: &Self) -> Option<Self> {
753 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
754 if y == 0 {
755 return Some(Self::nan());
756 }
757 return Some(match x % y {
758 rem if rem == 0 && x < 0 => Self::new(-0.0),
759 rem => Self::new(rem),
760 });
761 }
762 let x = self.as_number_cheap()?;
763 let y = other.as_number_cheap()?;
764 Some(Self::new((x % y).copysign(x)))
765 }
766
767 #[inline]
769 #[allow(clippy::float_cmp)]
770 pub(crate) fn pow_fast(&self, other: &Self) -> Option<Self> {
771 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
772 return Some(
773 u32::try_from(y)
774 .ok()
775 .and_then(|y| x.checked_pow(y))
776 .map_or_else(|| Self::new(f64::from(x).powi(y)), Self::new),
777 );
778 }
779 let x = self.as_number_cheap()?;
780 let y = other.as_number_cheap()?;
781 if x.abs() == 1.0 && y.is_infinite() {
782 Some(Self::nan())
783 } else {
784 Some(Self::new(x.powf(y)))
785 }
786 }
787
788 #[inline]
790 pub(crate) fn bitand_fast(&self, other: &Self) -> Option<Self> {
791 let x = self.0.as_integer32()?;
792 let y = other.0.as_integer32()?;
793 Some(Self::new(x & y))
794 }
795
796 #[inline]
798 pub(crate) fn bitor_fast(&self, other: &Self) -> Option<Self> {
799 let x = self.0.as_integer32()?;
800 let y = other.0.as_integer32()?;
801 Some(Self::new(x | y))
802 }
803
804 #[inline]
806 pub(crate) fn bitxor_fast(&self, other: &Self) -> Option<Self> {
807 let x = self.0.as_integer32()?;
808 let y = other.0.as_integer32()?;
809 Some(Self::new(x ^ y))
810 }
811
812 #[inline]
814 pub(crate) fn shl_fast(&self, other: &Self) -> Option<Self> {
815 let x = self.0.as_integer32()?;
816 let y = other.0.as_integer32()?;
817 Some(Self::new(x.wrapping_shl(y as u32)))
818 }
819
820 #[inline]
822 pub(crate) fn shr_fast(&self, other: &Self) -> Option<Self> {
823 let x = self.0.as_integer32()?;
824 let y = other.0.as_integer32()?;
825 Some(Self::new(x.wrapping_shr(y as u32)))
826 }
827
828 #[inline]
830 pub(crate) fn ushr_fast(&self, other: &Self) -> Option<Self> {
831 let x = self.0.as_integer32()?;
832 let y = other.0.as_integer32()?;
833 Some(Self::new((x as u32).wrapping_shr(y as u32)))
834 }
835
836 #[inline]
838 pub(crate) fn lt_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 le_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 gt_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 pub(crate) fn ge_fast(&self, other: &Self) -> Option<bool> {
872 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
873 return Some(x >= y);
874 }
875 let x = self.as_number_cheap()?;
876 let y = other.as_number_cheap()?;
877 Some(x >= y)
878 }
879
880 #[inline]
882 #[allow(clippy::float_cmp)]
883 pub(crate) fn equals_fast(&self, other: &Self) -> Option<Self> {
884 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
885 return Some(Self::new(x == y));
886 }
887 let x = self.as_number_cheap()?;
888 let y = other.as_number_cheap()?;
889 Some(Self::new(x == y))
890 }
891
892 #[inline]
894 #[allow(clippy::float_cmp)]
895 pub(crate) fn not_equals_fast(&self, other: &Self) -> Option<Self> {
896 if let (Some(x), Some(y)) = (self.0.as_integer32(), other.0.as_integer32()) {
897 return Some(Self::new(x != y));
898 }
899 let x = self.as_number_cheap()?;
900 let y = other.as_number_cheap()?;
901 Some(Self::new(x != y))
902 }
903}
904
905#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
913pub enum AbstractRelation {
914 True,
916 False,
918 Undefined,
920}
921
922impl From<bool> for AbstractRelation {
923 #[inline]
924 fn from(value: bool) -> Self {
925 if value { Self::True } else { Self::False }
926 }
927}