js_int/
int.rs

1use core::{
2    convert::TryFrom,
3    iter,
4    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
5    str::FromStr,
6};
7
8#[cfg(feature = "serde")]
9use serde::{
10    de::{Error as _, Unexpected},
11    Deserialize, Deserializer, Serialize,
12};
13
14use crate::{
15    error::{ParseIntError, ParseIntErrorKind, TryFromIntError},
16    UInt, MAX_SAFE_UINT,
17};
18
19/// The largest integer value that can be represented exactly by an f64.
20pub const MAX_SAFE_INT: i64 = 0x001F_FFFF_FFFF_FFFF;
21/// The smallest integer value that can be represented exactly by an f64.
22pub const MIN_SAFE_INT: i64 = -MAX_SAFE_INT;
23
24/// An integer limited to the range of integers that can be represented exactly by an f64.
25#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
26#[cfg_attr(feature = "serde", derive(Serialize))]
27pub struct Int(i64);
28
29impl Int {
30    /// The smallest value that can be represented by this integer type.
31    ///
32    /// # Examples
33    ///
34    /// Basic usage:
35    ///
36    /// ```
37    /// # use {core::convert::TryFrom, js_int::Int};
38    /// assert_eq!(Int::MIN, Int::try_from(-9_007_199_254_740_991i64).unwrap());
39    /// ```
40    pub const MIN: Self = Self(MIN_SAFE_INT);
41
42    /// The largest value that can be represented by this integer type.
43    ///
44    /// # Examples
45    ///
46    /// Basic usage:
47    ///
48    /// ```
49    /// # use {core::convert::TryFrom, js_int::Int};
50    /// assert_eq!(Int::MAX, Int::try_from(9_007_199_254_740_991i64).unwrap());
51    /// ```
52    pub const MAX: Self = Self(MAX_SAFE_INT);
53
54    /// Try to create an `Int` from the provided `i64`, returning `None` if it is smaller than
55    /// `MIN_SAFE_INT` or larger than `MAX_SAFE_INT`.
56    ///
57    /// This is the same as the `TryFrom<u64>` implementation for `Int`, except that it returns
58    /// an `Option` instead of a `Result`.
59    ///
60    /// # Examples
61    ///
62    /// Basic usage:
63    ///
64    /// ```
65    /// # use js_int::Int;
66    /// assert_eq!(Int::new(js_int::MIN_SAFE_INT), Some(Int::MIN));
67    /// assert_eq!(Int::new(js_int::MAX_SAFE_INT), Some(Int::MAX));
68    /// assert_eq!(Int::new(js_int::MIN_SAFE_INT - 1), None);
69    /// assert_eq!(Int::new(js_int::MAX_SAFE_INT + 1), None);
70    /// ```
71    #[must_use]
72    pub fn new(val: i64) -> Option<Self> {
73        if (MIN_SAFE_INT..=MAX_SAFE_INT).contains(&val) {
74            Some(Self(val))
75        } else {
76            None
77        }
78    }
79
80    /// Creates an `Int` from the given `i64` clamped to the safe interval.
81    ///
82    /// The given value gets clamped into the closed interval between
83    /// `MIN_SAFE_INT` and `MAX_SAFE_INT`.
84    ///
85    /// # Examples
86    ///
87    /// Basic usage:
88    ///
89    /// ```
90    /// # use js_int::{int, Int};
91    /// assert_eq!(Int::new_saturating(0), int!(0));
92    /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT), Int::MAX);
93    /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT + 1), Int::MAX);
94    /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT), Int::MIN);
95    /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT - 1), Int::MIN);
96    /// ```
97    #[must_use]
98    pub fn new_saturating(val: i64) -> Self {
99        if val < MIN_SAFE_INT {
100            Self::MIN
101        } else if val > MAX_SAFE_INT {
102            Self::MAX
103        } else {
104            Self(val)
105        }
106    }
107
108    /// The constructor used for arithmetic operations
109    #[must_use]
110    fn new_(val: i64) -> Self {
111        assert!(val >= MIN_SAFE_INT);
112        assert!(val <= MAX_SAFE_INT);
113
114        Self(val)
115    }
116
117    /// Helper function for mutable arithmetic operations (`+=`, `-=`, …)
118    fn assign_(&mut self, val: i64) {
119        assert!(val >= MIN_SAFE_INT);
120        assert!(val <= MAX_SAFE_INT);
121
122        *self = Self(val);
123    }
124
125    /// Converts a string slice in a given base to an integer.
126    ///
127    /// The string is expected to be an optional `+` or `-` sign followed by digits.
128    /// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
129    /// depending on `radix`:
130    ///
131    /// * `0-9`
132    /// * `a-z`
133    /// * `A-Z`
134    ///
135    /// # Panics
136    ///
137    /// This function panics if `radix` is not in the range from 2 to 36.
138    ///
139    /// # Examples
140    ///
141    /// Basic usage:
142    ///
143    /// ```
144    /// # use js_int::{int, Int};
145    /// assert_eq!(Int::from_str_radix("A", 16), Ok(int!(10)));
146    /// ```
147    pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
148        let val = i64::from_str_radix(src, radix)?;
149        if val < MIN_SAFE_INT {
150            Err(ParseIntError { kind: ParseIntErrorKind::Underflow })
151        } else if val > MAX_SAFE_INT {
152            Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
153        } else {
154            Ok(Self(val))
155        }
156    }
157
158    /// Returns the smallest value that can be represented by this integer type.
159    ///
160    /// # Examples
161    ///
162    /// Basic usage:
163    ///
164    /// ```
165    /// # use {core::convert::TryFrom, js_int::Int};
166    /// assert_eq!(Int::min_value(), Int::try_from(-9_007_199_254_740_991i64).unwrap());
167    /// ```
168    #[must_use]
169    #[deprecated = "Use `UInt::MIN` instead."]
170    pub const fn min_value() -> Self {
171        Self(MIN_SAFE_INT)
172    }
173
174    /// Returns the largest value that can be represented by this integer type.
175    ///
176    /// # Examples
177    ///
178    /// Basic usage:
179    ///
180    /// ```
181    /// # use {core::convert::TryFrom, js_int::Int};
182    /// assert_eq!(Int::max_value(), Int::try_from(9_007_199_254_740_991i64).unwrap());
183    /// ```
184    #[must_use]
185    #[deprecated = "Use `Int::MAX` instead."]
186    pub const fn max_value() -> Self {
187        Self(MAX_SAFE_INT)
188    }
189
190    /// Computes the absolute value of `self`.
191    ///
192    /// # Examples
193    ///
194    /// Basic usage:
195    ///
196    /// ```
197    /// # use js_int::{int, Int};
198    /// assert_eq!(int!(10).abs(), int!(10));
199    /// assert_eq!(int!(-10).abs(), int!(10));
200    ///
201    /// // Differently from i8 / i16 / i32 / i128, Int's min_value is its max_value negated
202    /// assert_eq!(Int::MIN.abs(), Int::MAX);
203    /// ```
204    #[must_use]
205    pub fn abs(self) -> Self {
206        Self(self.0.abs())
207    }
208
209    /// Returns `true` if `self` is positive and `false` if the number is zero or negative.
210    ///
211    /// # Examples
212    ///
213    /// Basic usage:
214    ///
215    /// ```
216    /// # use js_int::int;
217    /// assert!(int!(10).is_positive());
218    /// assert!(!int!(0).is_positive());
219    /// assert!(!int!(-10).is_positive());
220    /// ```
221    #[must_use]
222    pub const fn is_positive(self) -> bool {
223        self.0.is_positive()
224    }
225
226    /// Returns `true` if `self` is negative and `false` if the number is zero or positive.
227    ///
228    /// # Examples
229    ///
230    /// Basic usage:
231    ///
232    /// ```
233    /// # use js_int::int;
234    /// assert!(int!(-10).is_negative());
235    /// assert!(!int!(0).is_negative());
236    /// assert!(!int!(10).is_negative());
237    /// ```
238    #[must_use]
239    pub const fn is_negative(self) -> bool {
240        self.0.is_negative()
241    }
242
243    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow
244    /// occurred.
245    ///
246    /// # Examples
247    ///
248    /// Basic usage:
249    ///
250    /// ```
251    /// # use js_int::{int, Int};
252    /// assert_eq!(
253    ///     (Int::MAX - int!(1)).checked_add(int!(1)),
254    ///     Some(Int::MAX)
255    /// );
256    /// assert_eq!((Int::MAX - int!(1)).checked_add(int!(2)), None);
257    /// ```
258    #[must_use]
259    pub fn checked_add(self, rhs: Self) -> Option<Self> {
260        self.0.checked_add(rhs.0).and_then(Self::new)
261    }
262
263    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow
264    /// occurred.
265    ///
266    /// # Examples
267    ///
268    /// Basic usage:
269    ///
270    /// ```
271    /// # use js_int::{int, Int};
272    /// assert_eq!(
273    ///     (Int::MIN + int!(2)).checked_sub(int!(1)),
274    ///     Some(Int::MIN + int!(1))
275    /// );
276    /// assert_eq!((Int::MIN + int!(2)).checked_sub(int!(3)), None);
277    /// ```
278    #[must_use]
279    pub fn checked_sub(self, rhs: Self) -> Option<Self> {
280        self.0.checked_sub(rhs.0).and_then(Self::new)
281    }
282
283    /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow
284    /// occurred.
285    ///
286    /// # Examples
287    ///
288    /// Basic usage:
289    ///
290    /// ```
291    /// # use js_int::{int, Int};
292    /// assert_eq!(int!(5).checked_mul(int!(1)), Some(int!(5)));
293    /// assert_eq!(Int::MAX.checked_mul(int!(2)), None);
294    /// ```
295    #[must_use]
296    pub fn checked_mul(self, rhs: Self) -> Option<Self> {
297        self.0.checked_mul(rhs.0).and_then(Self::new)
298    }
299
300    /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`.
301    ///
302    /// # Examples
303    ///
304    /// Basic usage:
305    ///
306    /// ```
307    /// # use js_int::{int, Int};
308    /// assert_eq!(Int::MIN.checked_div(int!(-1)), Some(Int::MAX));
309    /// assert_eq!(int!(1).checked_div(int!(0)), None);
310    /// ```
311    #[must_use]
312    pub fn checked_div(self, rhs: Self) -> Option<Self> {
313        self.0.checked_div(rhs.0).map(Self)
314    }
315
316    /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`.
317    ///
318    /// # Examples
319    ///
320    /// Basic usage:
321    ///
322    /// ```
323    /// # use js_int::{int, Int};
324    /// assert_eq!(int!(5).checked_rem(int!(2)), Some(int!(1)));
325    /// assert_eq!(int!(5).checked_rem(int!(0)), None);
326    /// assert_eq!(Int::MIN.checked_rem(int!(-1)), Some(int!(0)));
327    /// ```
328    #[must_use]
329    pub fn checked_rem(self, rhs: Self) -> Option<Self> {
330        self.0.checked_rem(rhs.0).map(Self)
331    }
332
333    /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if overflow or
334    /// underflow occurred.
335    ///
336    /// # Examples
337    ///
338    /// Basic usage:
339    ///
340    /// ```
341    /// # use js_int::{int, Int};
342    /// assert_eq!(int!(8).checked_pow(2), Some(int!(64)));
343    /// assert_eq!(Int::MAX.checked_pow(2), None);
344    /// assert_eq!(Int::MIN.checked_pow(2), None);
345    /// assert_eq!(int!(1_000_000_000).checked_pow(2), None);
346    /// ```
347    #[must_use]
348    pub fn checked_pow(self, exp: u32) -> Option<Self> {
349        self.0.checked_pow(exp).and_then(Self::new)
350    }
351
352    /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds
353    /// instead of overflowing.
354    ///
355    /// # Examples
356    ///
357    /// Basic usage:
358    ///
359    /// ```
360    /// # use js_int::{int, Int};
361    /// assert_eq!(int!(100).saturating_add(int!(1)), int!(101));
362    /// assert_eq!(Int::MAX.saturating_add(int!(1)), Int::MAX);
363    /// assert_eq!(Int::MIN.saturating_add(int!(-1)), Int::MIN);
364    /// ```
365    #[must_use]
366    pub fn saturating_add(self, rhs: Self) -> Self {
367        self.checked_add(rhs).unwrap_or_else(|| if self > int!(0) { Self::MAX } else { Self::MIN })
368    }
369
370    /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric
371    /// bounds instead of underflowing.
372    ///
373    /// # Examples
374    ///
375    /// Basic usage:
376    ///
377    /// ```
378    /// # use js_int::{int, Int};
379    /// assert_eq!(int!(100).saturating_sub(int!(1)), int!(99));
380    /// assert_eq!(Int::MIN.saturating_sub(int!(1)), Int::MIN);
381    /// assert_eq!(Int::MAX.saturating_sub(int!(-1)), Int::MAX);
382    /// ```
383    #[must_use]
384    pub fn saturating_sub(self, rhs: Self) -> Self {
385        self.checked_sub(rhs).unwrap_or_else(|| if self > int!(0) { Self::MAX } else { Self::MIN })
386    }
387
388    /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric
389    /// bounds instead of overflowing.
390    ///
391    /// # Examples
392    ///
393    /// Basic usage:
394    ///
395    /// ```
396    /// # use js_int::{int, Int};
397    /// assert_eq!(int!(100).saturating_mul(int!(2)), int!(200));
398    /// assert_eq!(Int::MAX.saturating_mul(int!(2)), Int::MAX);
399    /// assert_eq!(Int::MAX.saturating_mul(Int::MAX), Int::MAX);
400    /// assert_eq!(Int::MAX.saturating_mul(Int::MIN), Int::MIN);
401    /// ```
402    #[must_use]
403    pub fn saturating_mul(self, rhs: Self) -> Self {
404        Self::new_saturating(self.0.saturating_mul(rhs.0))
405    }
406
407    /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the
408    /// numeric bounds instead of overflowing or underflowing.
409    ///
410    /// # Examples
411    ///
412    /// Basic usage:
413    ///
414    /// ```
415    /// # use js_int::{int, Int};
416    /// assert_eq!(int!(5).saturating_pow(2), int!(25));
417    /// assert_eq!(int!(-2).saturating_pow(3), int!(-8));
418    /// assert_eq!(Int::MAX.saturating_pow(2), Int::MAX);
419    /// assert_eq!(Int::MIN.saturating_pow(2), Int::MAX);
420    /// ```
421    #[must_use]
422    pub fn saturating_pow(self, exp: u32) -> Self {
423        Self::new_saturating(self.0.saturating_pow(exp))
424    }
425
426    // TODO: wrapping_* methods, overflowing_* methods
427}
428
429fmt_impls!(Int);
430convert_impls!(Int, i8, i16, i32, i64, i128, isize, u8, u16, u32, usize);
431
432impl From<u8> for Int {
433    fn from(val: u8) -> Self {
434        Self(i64::from(val))
435    }
436}
437
438impl From<u16> for Int {
439    fn from(val: u16) -> Self {
440        Self(i64::from(val))
441    }
442}
443
444impl From<u32> for Int {
445    fn from(val: u32) -> Self {
446        Self(i64::from(val))
447    }
448}
449
450impl From<UInt> for Int {
451    fn from(val: UInt) -> Self {
452        Self(i64::from(val))
453    }
454}
455
456impl TryFrom<u64> for Int {
457    type Error = TryFromIntError;
458
459    fn try_from(val: u64) -> Result<Self, TryFromIntError> {
460        if val <= MAX_SAFE_UINT {
461            Ok(Self(val as i64))
462        } else {
463            Err(TryFromIntError::new())
464        }
465    }
466}
467
468impl TryFrom<u128> for Int {
469    type Error = TryFromIntError;
470
471    fn try_from(val: u128) -> Result<Self, TryFromIntError> {
472        if val <= u128::from(MAX_SAFE_UINT) {
473            Ok(Self(val as i64))
474        } else {
475            Err(TryFromIntError::new())
476        }
477    }
478}
479
480macro_rules! int_op_impl {
481    ($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => {
482        impl $trait for Int {
483            type Output = Self;
484
485            fn $method(self, rhs: Self) -> Self {
486                Self::new_(<i64 as $trait>::$method(self.0, rhs.0))
487            }
488        }
489
490        impl $assign_trait for Int {
491            fn $assign_method(&mut self, other: Self) {
492                self.assign_(<i64 as $trait>::$method(self.0, other.0));
493            }
494        }
495    };
496}
497
498int_op_impl!(Add, add, AddAssign, add_assign);
499int_op_impl!(Sub, sub, SubAssign, sub_assign);
500int_op_impl!(Mul, mul, MulAssign, mul_assign);
501int_op_impl!(Div, div, DivAssign, div_assign);
502int_op_impl!(Rem, rem, RemAssign, rem_assign);
503
504impl Neg for Int {
505    type Output = Self;
506
507    fn neg(self) -> Self {
508        Self(-self.0)
509    }
510}
511
512impl iter::Sum for Int {
513    fn sum<I>(iter: I) -> Self
514    where
515        I: Iterator<Item = Int>,
516    {
517        Self::new_(iter.map(|x| x.0).sum())
518    }
519}
520
521impl<'a> iter::Sum<&'a Int> for Int {
522    fn sum<I>(iter: I) -> Self
523    where
524        I: Iterator<Item = &'a Int>,
525    {
526        Self::new_(iter.map(|x| x.0).sum())
527    }
528}
529
530impl iter::Product for Int {
531    fn product<I>(iter: I) -> Self
532    where
533        I: Iterator<Item = Int>,
534    {
535        Self::new_(iter.map(|x| x.0).product())
536    }
537}
538
539impl<'a> iter::Product<&'a Int> for Int {
540    fn product<I>(iter: I) -> Self
541    where
542        I: Iterator<Item = &'a Int>,
543    {
544        Self::new_(iter.map(|x| x.0).product())
545    }
546}
547
548impl FromStr for Int {
549    type Err = ParseIntError;
550
551    fn from_str(src: &str) -> Result<Self, Self::Err> {
552        let val = i64::from_str(src)?;
553        if val < MIN_SAFE_INT {
554            Err(ParseIntError { kind: ParseIntErrorKind::Underflow })
555        } else if val > MAX_SAFE_INT {
556            Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
557        } else {
558            Ok(Self(val))
559        }
560    }
561}
562
563#[cfg(feature = "serde")]
564impl<'de> Deserialize<'de> for Int {
565    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
566    where
567        D: Deserializer<'de>,
568    {
569        #[cfg(not(feature = "float_deserialize"))]
570        {
571            let val = i64::deserialize(deserializer)?;
572
573            Self::new(val).ok_or_else(|| {
574                D::Error::invalid_value(
575                    Unexpected::Signed(val),
576                    &"an integer between -2^53 + 1 and 2^53 - 1",
577                )
578            })
579        }
580
581        #[cfg(feature = "float_deserialize")]
582        {
583            #[cfg(not(feature = "lax_deserialize"))]
584            const EXPECTING: &str =
585                "a number between -2^53 + 1 and 2^53 - 1 without fractional component";
586            #[cfg(feature = "lax_deserialize")]
587            const EXPECTING: &str = "a number between -2^53 + 1 and 2^53 - 1";
588
589            let val = f64::deserialize(deserializer)?;
590
591            if val > MAX_SAFE_INT as f64
592                || val < MIN_SAFE_INT as f64
593                || !super::is_acceptable_float(val)
594            {
595                Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING))
596            } else {
597                Ok(Self(val as i64))
598            }
599        }
600    }
601}
602
603#[cfg(test)]
604mod tests {
605    use super::Int;
606
607    #[test]
608    fn int_ops() {
609        assert_eq!(int!(5) + int!(3), int!(8));
610        assert_eq!(int!(1) - int!(2), int!(-1));
611        assert_eq!(int!(4) * int!(-7), int!(-28));
612        assert_eq!(int!(5) / int!(2), int!(2));
613        assert_eq!(int!(9) % int!(3), int!(0));
614    }
615
616    #[test]
617    fn int_assign_ops() {
618        let mut int = int!(1);
619
620        int += int!(1);
621        assert_eq!(int, int!(2));
622
623        int -= int!(-1);
624        assert_eq!(int, int!(3));
625
626        int *= int!(3);
627        assert_eq!(int, int!(9));
628
629        int /= int!(3);
630        assert_eq!(int, int!(3));
631
632        int %= int!(2);
633        assert_eq!(int, int!(1));
634    }
635
636    #[test]
637    #[should_panic]
638    fn int_underflow_panic() {
639        let _ = Int::MIN - int!(1);
640    }
641
642    #[test]
643    #[should_panic]
644    fn int_overflow_panic() {
645        let _ = Int::MAX + int!(1);
646    }
647
648    #[test]
649    fn try_from_int_for_u_n() {
650        use core::convert::TryFrom;
651        let u8_max = u8::MAX as i64;
652        let u16_max = u16::MAX as i64;
653        let u32_max = u32::MAX as i64;
654
655        assert_eq!(u8::try_from(Int(0)), Ok(0));
656        assert_eq!(u8::try_from(Int(10)), Ok(10));
657        assert_eq!(u8::try_from(Int(u8_max)), Ok(u8::MAX));
658        assert!(u8::try_from(Int(u8_max + 1)).is_err());
659        assert!(u8::try_from(Int(-1)).is_err());
660        assert!(u8::try_from(Int(-10)).is_err());
661
662        assert_eq!(u16::try_from(Int(0)), Ok(0));
663        assert_eq!(u16::try_from(Int(1000)), Ok(1000));
664        assert_eq!(u16::try_from(Int(u8_max + 1)), Ok((u8_max + 1) as u16));
665        assert_eq!(u16::try_from(Int(u16_max)), Ok(u16::MAX));
666        assert!(u16::try_from(Int(u16_max + 1)).is_err());
667        assert!(u16::try_from(Int(-1)).is_err());
668        assert!(u16::try_from(Int(-10)).is_err());
669
670        assert_eq!(u32::try_from(Int(0)), Ok(0));
671        assert_eq!(u32::try_from(Int(1000)), Ok(1000));
672        assert_eq!(u32::try_from(Int(u16_max + 1)), Ok((u16_max + 1) as u32));
673        assert_eq!(u32::try_from(Int(u32_max)), Ok(u32::MAX));
674        assert!(u32::try_from(Int(u32_max + 1)).is_err());
675        assert!(u32::try_from(Int(-1)).is_err());
676        assert!(u32::try_from(Int(-10)).is_err());
677    }
678}