cosmwasm_std/math/
int64.rs

1use alloc::string::{String, ToString};
2use core::fmt;
3use core::ops::{
4    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr,
5    ShrAssign, Sub, SubAssign,
6};
7use core::str::FromStr;
8
9use crate::errors::{
10    DivideByZeroError, DivisionError, ErrorKind, OverflowError, OverflowOperation, StdError,
11};
12use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
13use crate::{
14    CheckedMultiplyRatioError, Int128, Int256, Int512, Uint128, Uint256, Uint512, Uint64,
15    __internal::forward_ref_partial_eq,
16};
17
18use super::conversion::{
19    forward_try_from, from_and_to_bytes, primitive_to_wrapped_int, try_from_int_to_int,
20    wrapped_int_to_primitive,
21};
22use super::impl_int_serde;
23use super::num_consts::NumConsts;
24
25/// An implementation of i64 that is using strings for JSON encoding/decoding,
26/// such that the full i64 range can be used for clients that convert JSON numbers to floats,
27/// like JavaScript and jq.
28///
29/// # Examples
30///
31/// Use `from` to create instances of this and `i64` to get the value out:
32///
33/// ```
34/// # use cosmwasm_std::Int64;
35/// let a = Int64::from(258i64);
36/// assert_eq!(a.i64(), 258);
37/// ```
38#[derive(
39    Copy,
40    Clone,
41    Default,
42    Debug,
43    PartialEq,
44    Eq,
45    PartialOrd,
46    Ord,
47    schemars::JsonSchema,
48    cw_schema::Schemaifier,
49)]
50#[schemaifier(type = cw_schema::NodeType::Integer { precision: 64, signed: true })]
51pub struct Int64(#[schemars(with = "String")] pub(crate) i64);
52
53impl_int_serde!(Int64);
54forward_ref_partial_eq!(Int64, Int64);
55
56impl Int64 {
57    pub const MAX: Int64 = Int64(i64::MAX);
58    pub const MIN: Int64 = Int64(i64::MIN);
59
60    /// Creates a Int64(value).
61    ///
62    /// This method is less flexible than `from` but can be called in a const context.
63    #[inline]
64    #[must_use]
65    pub const fn new(value: i64) -> Self {
66        Self(value)
67    }
68
69    /// Creates a Int64(0)
70    #[inline]
71    pub const fn zero() -> Self {
72        Int64(0)
73    }
74
75    /// Creates a Int64(1)
76    #[inline]
77    pub const fn one() -> Self {
78        Self(1)
79    }
80
81    /// Returns a copy of the internal data
82    pub const fn i64(&self) -> i64 {
83        self.0
84    }
85
86    from_and_to_bytes!(i64, 8);
87
88    #[must_use]
89    pub const fn is_zero(&self) -> bool {
90        self.0 == 0
91    }
92
93    #[must_use]
94    pub const fn is_negative(&self) -> bool {
95        self.0.is_negative()
96    }
97
98    #[must_use = "this returns the result of the operation, without modifying the original"]
99    pub const fn pow(self, exp: u32) -> Self {
100        match self.0.checked_pow(exp) {
101            Some(val) => Self(val),
102            None => panic!("attempt to exponentiate with overflow"),
103        }
104    }
105
106    /// Returns `self * numerator / denominator`.
107    ///
108    /// Due to the nature of the integer division involved, the result is always floored.
109    /// E.g. 5 * 99/100 = 4.
110    pub fn checked_multiply_ratio<A: Into<Self>, B: Into<Self>>(
111        &self,
112        numerator: A,
113        denominator: B,
114    ) -> Result<Self, CheckedMultiplyRatioError> {
115        let numerator = numerator.into();
116        let denominator = denominator.into();
117        if denominator.is_zero() {
118            return Err(CheckedMultiplyRatioError::DivideByZero);
119        }
120        match (self.full_mul(numerator) / Int128::from(denominator)).try_into() {
121            Ok(ratio) => Ok(ratio),
122            Err(_) => Err(CheckedMultiplyRatioError::Overflow),
123        }
124    }
125
126    /// Multiplies two [`Int64`] values without overflow, producing an
127    /// [`Int128`].
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use cosmwasm_std::Int64;
133    ///
134    /// let a = Int64::MAX;
135    /// let result = a.full_mul(2i32);
136    /// assert_eq!(result.to_string(), "18446744073709551614");
137    /// ```
138    #[must_use = "this returns the result of the operation, without modifying the original"]
139    pub fn full_mul(self, rhs: impl Into<Self>) -> Int128 {
140        Int128::from(self)
141            .checked_mul(Int128::from(rhs.into()))
142            .unwrap()
143    }
144
145    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
146        self.0
147            .checked_add(other.0)
148            .map(Self)
149            .ok_or_else(|| OverflowError::new(OverflowOperation::Add))
150    }
151
152    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
153        self.0
154            .checked_sub(other.0)
155            .map(Self)
156            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub))
157    }
158
159    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
160        self.0
161            .checked_mul(other.0)
162            .map(Self)
163            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul))
164    }
165
166    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
167        self.0
168            .checked_pow(exp)
169            .map(Self)
170            .ok_or_else(|| OverflowError::new(OverflowOperation::Pow))
171    }
172
173    pub fn checked_div(self, other: Self) -> Result<Self, DivisionError> {
174        if other.is_zero() {
175            return Err(DivisionError::DivideByZero);
176        }
177        self.0
178            .checked_div(other.0)
179            .map(Self)
180            .ok_or(DivisionError::Overflow)
181    }
182
183    pub fn checked_div_euclid(self, other: Self) -> Result<Self, DivisionError> {
184        if other.is_zero() {
185            return Err(DivisionError::DivideByZero);
186        }
187        self.0
188            .checked_div_euclid(other.0)
189            .map(Self)
190            .ok_or(DivisionError::Overflow)
191    }
192
193    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
194        self.0
195            .checked_rem(other.0)
196            .map(Self)
197            .ok_or(DivideByZeroError)
198    }
199
200    pub fn checked_shr(self, other: u32) -> Result<Self, OverflowError> {
201        if other >= 64 {
202            return Err(OverflowError::new(OverflowOperation::Shr));
203        }
204
205        Ok(Self(self.0.shr(other)))
206    }
207
208    pub fn checked_shl(self, other: u32) -> Result<Self, OverflowError> {
209        if other >= 64 {
210            return Err(OverflowError::new(OverflowOperation::Shl));
211        }
212
213        Ok(Self(self.0.shl(other)))
214    }
215
216    #[must_use = "this returns the result of the operation, without modifying the original"]
217    #[inline]
218    pub fn wrapping_add(self, other: Self) -> Self {
219        Self(self.0.wrapping_add(other.0))
220    }
221
222    #[must_use = "this returns the result of the operation, without modifying the original"]
223    #[inline]
224    pub fn wrapping_sub(self, other: Self) -> Self {
225        Self(self.0.wrapping_sub(other.0))
226    }
227
228    #[must_use = "this returns the result of the operation, without modifying the original"]
229    #[inline]
230    pub fn wrapping_mul(self, other: Self) -> Self {
231        Self(self.0.wrapping_mul(other.0))
232    }
233
234    #[must_use = "this returns the result of the operation, without modifying the original"]
235    #[inline]
236    pub fn wrapping_pow(self, other: u32) -> Self {
237        Self(self.0.wrapping_pow(other))
238    }
239
240    #[must_use = "this returns the result of the operation, without modifying the original"]
241    pub fn saturating_add(self, other: Self) -> Self {
242        Self(self.0.saturating_add(other.0))
243    }
244
245    #[must_use = "this returns the result of the operation, without modifying the original"]
246    pub fn saturating_sub(self, other: Self) -> Self {
247        Self(self.0.saturating_sub(other.0))
248    }
249
250    #[must_use = "this returns the result of the operation, without modifying the original"]
251    pub fn saturating_mul(self, other: Self) -> Self {
252        Self(self.0.saturating_mul(other.0))
253    }
254
255    #[must_use = "this returns the result of the operation, without modifying the original"]
256    pub fn saturating_pow(self, exp: u32) -> Self {
257        Self(self.0.saturating_pow(exp))
258    }
259
260    #[must_use = "this returns the result of the operation, without modifying the original"]
261    pub const fn abs_diff(self, other: Self) -> Uint64 {
262        Uint64(self.0.abs_diff(other.0))
263    }
264
265    #[must_use = "this returns the result of the operation, without modifying the original"]
266    pub const fn abs(self) -> Self {
267        match self.0.checked_abs() {
268            Some(val) => Self(val),
269            None => panic!("attempt to calculate absolute value with overflow"),
270        }
271    }
272
273    #[must_use = "this returns the result of the operation, without modifying the original"]
274    pub const fn unsigned_abs(self) -> Uint64 {
275        Uint64(self.0.unsigned_abs())
276    }
277
278    /// Strict negation. Computes -self, panicking if self == MIN.
279    ///
280    /// This is the same as [`Int64::neg`] but const.
281    pub const fn strict_neg(self) -> Self {
282        match self.0.checked_neg() {
283            Some(val) => Self(val),
284            None => panic!("attempt to negate with overflow"),
285        }
286    }
287}
288
289impl NumConsts for Int64 {
290    const ZERO: Self = Self::zero();
291    const ONE: Self = Self::one();
292    const MAX: Self = Self::MAX;
293    const MIN: Self = Self::MIN;
294}
295
296// uint to Int
297primitive_to_wrapped_int!(u8, Int64);
298primitive_to_wrapped_int!(u16, Int64);
299primitive_to_wrapped_int!(u32, Int64);
300
301// int to Int
302primitive_to_wrapped_int!(i8, Int64);
303primitive_to_wrapped_int!(i16, Int64);
304primitive_to_wrapped_int!(i32, Int64);
305primitive_to_wrapped_int!(i64, Int64);
306
307// Int to int
308wrapped_int_to_primitive!(Int64, i64);
309wrapped_int_to_primitive!(Int64, i128);
310
311// Int to Int
312try_from_int_to_int!(Int128, Int64);
313try_from_int_to_int!(Int256, Int64);
314try_from_int_to_int!(Int512, Int64);
315
316// Uint to Int
317forward_try_from!(Uint64, Int64);
318forward_try_from!(Uint128, Int64);
319forward_try_from!(Uint256, Int64);
320forward_try_from!(Uint512, Int64);
321
322impl TryFrom<&str> for Int64 {
323    type Error = StdError;
324
325    fn try_from(val: &str) -> Result<Self, Self::Error> {
326        Self::from_str(val)
327    }
328}
329
330impl FromStr for Int64 {
331    type Err = StdError;
332
333    fn from_str(s: &str) -> Result<Self, Self::Err> {
334        match s.parse::<i64>() {
335            Ok(u) => Ok(Self(u)),
336            Err(e) => {
337                Err(StdError::msg(format_args!("Parsing Int64: {e}")).with_kind(ErrorKind::Parsing))
338            }
339        }
340    }
341}
342
343impl From<Int64> for String {
344    fn from(original: Int64) -> Self {
345        original.to_string()
346    }
347}
348
349impl fmt::Display for Int64 {
350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351        self.0.fmt(f)
352    }
353}
354
355impl Add<Int64> for Int64 {
356    type Output = Self;
357
358    fn add(self, rhs: Self) -> Self {
359        Int64(self.0.checked_add(rhs.0).unwrap())
360    }
361}
362forward_ref_binop!(impl Add, add for Int64, Int64);
363
364impl Sub<Int64> for Int64 {
365    type Output = Self;
366
367    fn sub(self, rhs: Self) -> Self {
368        Int64(self.0.checked_sub(rhs.0).unwrap())
369    }
370}
371forward_ref_binop!(impl Sub, sub for Int64, Int64);
372
373impl SubAssign<Int64> for Int64 {
374    fn sub_assign(&mut self, rhs: Int64) {
375        self.0 = self.0.checked_sub(rhs.0).unwrap();
376    }
377}
378forward_ref_op_assign!(impl SubAssign, sub_assign for Int64, Int64);
379
380impl Div<Int64> for Int64 {
381    type Output = Self;
382
383    fn div(self, rhs: Self) -> Self::Output {
384        Self(self.0.checked_div(rhs.0).unwrap())
385    }
386}
387forward_ref_binop!(impl Div, div for Int64, Int64);
388
389impl Rem for Int64 {
390    type Output = Self;
391
392    /// # Panics
393    ///
394    /// This operation will panic if `rhs` is zero.
395    #[inline]
396    fn rem(self, rhs: Self) -> Self {
397        Self(self.0.rem(rhs.0))
398    }
399}
400forward_ref_binop!(impl Rem, rem for Int64, Int64);
401
402impl Not for Int64 {
403    type Output = Self;
404
405    fn not(self) -> Self::Output {
406        Self(!self.0)
407    }
408}
409
410impl Neg for Int64 {
411    type Output = Self;
412
413    fn neg(self) -> Self::Output {
414        self.strict_neg()
415    }
416}
417
418impl RemAssign<Int64> for Int64 {
419    fn rem_assign(&mut self, rhs: Int64) {
420        *self = *self % rhs;
421    }
422}
423forward_ref_op_assign!(impl RemAssign, rem_assign for Int64, Int64);
424
425impl Mul<Int64> for Int64 {
426    type Output = Self;
427
428    fn mul(self, rhs: Self) -> Self::Output {
429        Self(self.0.checked_mul(rhs.0).unwrap())
430    }
431}
432forward_ref_binop!(impl Mul, mul for Int64, Int64);
433
434impl MulAssign<Int64> for Int64 {
435    fn mul_assign(&mut self, rhs: Self) {
436        self.0 = self.0.checked_mul(rhs.0).unwrap();
437    }
438}
439forward_ref_op_assign!(impl MulAssign, mul_assign for Int64, Int64);
440
441impl Shr<u32> for Int64 {
442    type Output = Self;
443
444    fn shr(self, rhs: u32) -> Self::Output {
445        self.checked_shr(rhs).unwrap_or_else(|_| {
446            panic!("right shift error: {rhs} is larger or equal than the number of bits in Int64",)
447        })
448    }
449}
450forward_ref_binop!(impl Shr, shr for Int64, u32);
451
452impl Shl<u32> for Int64 {
453    type Output = Self;
454
455    fn shl(self, rhs: u32) -> Self::Output {
456        self.checked_shl(rhs).unwrap_or_else(|_| {
457            panic!("left shift error: {rhs} is larger or equal than the number of bits in Int64",)
458        })
459    }
460}
461forward_ref_binop!(impl Shl, shl for Int64, u32);
462
463impl AddAssign<Int64> for Int64 {
464    fn add_assign(&mut self, rhs: Int64) {
465        self.0 = self.0.checked_add(rhs.0).unwrap();
466    }
467}
468forward_ref_op_assign!(impl AddAssign, add_assign for Int64, Int64);
469
470impl DivAssign<Int64> for Int64 {
471    fn div_assign(&mut self, rhs: Self) {
472        self.0 = self.0.checked_div(rhs.0).unwrap();
473    }
474}
475forward_ref_op_assign!(impl DivAssign, div_assign for Int64, Int64);
476
477impl ShrAssign<u32> for Int64 {
478    fn shr_assign(&mut self, rhs: u32) {
479        *self = Shr::<u32>::shr(*self, rhs);
480    }
481}
482forward_ref_op_assign!(impl ShrAssign, shr_assign for Int64, u32);
483
484impl ShlAssign<u32> for Int64 {
485    fn shl_assign(&mut self, rhs: u32) {
486        *self = Shl::<u32>::shl(*self, rhs);
487    }
488}
489forward_ref_op_assign!(impl ShlAssign, shl_assign for Int64, u32);
490
491impl<A> core::iter::Sum<A> for Int64
492where
493    Self: Add<A, Output = Self>,
494{
495    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
496        iter.fold(Self::zero(), Add::add)
497    }
498}
499
500#[cfg(test)]
501mod tests {
502    use super::*;
503    use crate::math::conversion::test_try_from_uint_to_int;
504
505    #[test]
506    fn size_of_works() {
507        assert_eq!(core::mem::size_of::<Int64>(), 8);
508    }
509
510    #[test]
511    fn int64_from_be_bytes_works() {
512        // zero
513        let original = [0; 8];
514        let num = Int64::from_be_bytes(original);
515        assert!(num.is_zero());
516
517        // one
518        let original = [0, 0, 0, 0, 0, 0, 0, 1];
519        let num = Int64::from_be_bytes(original);
520        assert_eq!(num.i64(), 1);
521
522        // 258
523        let original = [0, 0, 0, 0, 0, 0, 1, 2];
524        let num = Int64::from_be_bytes(original);
525        assert_eq!(num.i64(), 258);
526
527        // 2x roundtrip
528        let original = [1; 8];
529        let num = Int64::from_be_bytes(original);
530        let a: [u8; 8] = num.to_be_bytes();
531        assert_eq!(a, original);
532
533        let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
534        let num = Int64::from_be_bytes(original);
535        let a: [u8; 8] = num.to_be_bytes();
536        assert_eq!(a, original);
537    }
538
539    #[test]
540    fn int64_from_le_bytes_works() {
541        // zero
542        let original = [0; 8];
543        let num = Int64::from_le_bytes(original);
544        assert!(num.is_zero());
545
546        // one
547        let original = [1, 0, 0, 0, 0, 0, 0, 0];
548        let num = Int64::from_le_bytes(original);
549        assert_eq!(num.i64(), 1);
550
551        // 258
552        let original = [2, 1, 0, 0, 0, 0, 0, 0];
553        let num = Int64::from_le_bytes(original);
554        assert_eq!(num.i64(), 258);
555
556        // 2x roundtrip
557        let original = [1; 8];
558        let num = Int64::from_le_bytes(original);
559        let a: [u8; 8] = num.to_le_bytes();
560        assert_eq!(a, original);
561
562        let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
563        let num = Int64::from_le_bytes(original);
564        let a: [u8; 8] = num.to_le_bytes();
565        assert_eq!(a, original);
566    }
567
568    #[test]
569    fn int64_new_works() {
570        let num = Int64::new(222);
571        assert_eq!(num.i64(), 222);
572
573        let num = Int64::new(-222);
574        assert_eq!(num.i64(), -222);
575
576        let num = Int64::new(i64::MAX);
577        assert_eq!(num.i64(), i64::MAX);
578
579        let num = Int64::new(i64::MIN);
580        assert_eq!(num.i64(), i64::MIN);
581    }
582
583    #[test]
584    fn int64_not_works() {
585        assert_eq!(!Int64::new(222), Int64::new(!222));
586        assert_eq!(!Int64::new(-222), Int64::new(!-222));
587
588        assert_eq!(!Int64::MAX, Int64::new(!i64::MAX));
589        assert_eq!(!Int64::MIN, Int64::new(!i64::MIN));
590    }
591
592    #[test]
593    fn int64_zero_works() {
594        let zero = Int64::zero();
595        assert_eq!(zero.to_be_bytes(), [0; 8]);
596    }
597
598    #[test]
599    fn uint64_one_works() {
600        let one = Int64::one();
601        let mut one_be = [0; 8];
602        one_be[7] = 1;
603
604        assert_eq!(one.to_be_bytes(), one_be);
605    }
606
607    #[test]
608    fn int64_endianness() {
609        let be_bytes = [0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
610        let le_bytes = [3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8];
611
612        // These should all be the same.
613        let num1 = Int64::from_be_bytes(be_bytes);
614        let num2 = Int64::from_le_bytes(le_bytes);
615        assert_eq!(num1, Int64::from(65536u32 + 512 + 3));
616        assert_eq!(num1, num2);
617    }
618
619    #[test]
620    fn int64_convert_to() {
621        let a = Int64::new(5);
622        assert_eq!(i64::from(a), 5);
623
624        let a = Int64::new(5);
625        assert_eq!(i128::from(a), 5);
626    }
627
628    #[test]
629    fn int64_convert_from() {
630        let a = Int64::from(5i64);
631        assert_eq!(a.0, i64::from(5u32));
632
633        let a = Int64::from(5i64);
634        assert_eq!(a.0, i64::from(5u32));
635
636        let a = Int64::from(5u32);
637        assert_eq!(a.0, i64::from(5u32));
638
639        let a = Int64::from(5u16);
640        assert_eq!(a.0, i64::from(5u32));
641
642        let a = Int64::from(5u8);
643        assert_eq!(a.0, i64::from(5u32));
644
645        let a = Int64::from(-5i64);
646        assert_eq!(a.0, i64::from(-5i32));
647
648        let a = Int64::from(-5i64);
649        assert_eq!(a.0, i64::from(-5i32));
650
651        let a = Int64::from(-5i32);
652        assert_eq!(a.0, i64::from(-5i32));
653
654        let a = Int64::from(-5i16);
655        assert_eq!(a.0, i64::from(-5i32));
656
657        let a = Int64::from(-5i8);
658        assert_eq!(a.0, i64::from(-5i32));
659
660        let result = Int64::try_from("34567");
661        assert_eq!(result.unwrap().0, "34567".parse::<i64>().unwrap());
662
663        let result = Int64::try_from("1.23");
664        assert!(result.is_err());
665    }
666
667    #[test]
668    fn int64_try_from_unsigned_works() {
669        test_try_from_uint_to_int::<Uint64, Int64>("Uint64", "Int64");
670        test_try_from_uint_to_int::<Uint128, Int64>("Uint128", "Int64");
671        test_try_from_uint_to_int::<Uint256, Int64>("Uint256", "Int64");
672        test_try_from_uint_to_int::<Uint512, Int64>("Uint512", "Int64");
673    }
674
675    #[test]
676    fn int64_implements_display() {
677        let a = Int64::from(12345u32);
678        assert_eq!(format!("Embedded: {a}"), "Embedded: 12345");
679        assert_eq!(a.to_string(), "12345");
680
681        let a = Int64::from(-12345i32);
682        assert_eq!(format!("Embedded: {a}"), "Embedded: -12345");
683        assert_eq!(a.to_string(), "-12345");
684
685        let a = Int64::zero();
686        assert_eq!(format!("Embedded: {a}"), "Embedded: 0");
687        assert_eq!(a.to_string(), "0");
688    }
689
690    #[test]
691    fn int64_display_padding_works() {
692        // width > natural representation
693        let a = Int64::from(123i64);
694        assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
695        let a = Int64::from(-123i64);
696        assert_eq!(format!("Embedded: {a:05}"), "Embedded: -0123");
697
698        // width < natural representation
699        let a = Int64::from(123i64);
700        assert_eq!(format!("Embedded: {a:02}"), "Embedded: 123");
701        let a = Int64::from(-123i64);
702        assert_eq!(format!("Embedded: {a:02}"), "Embedded: -123");
703    }
704
705    #[test]
706    fn int64_to_be_bytes_works() {
707        assert_eq!(Int64::zero().to_be_bytes(), [0; 8]);
708
709        let mut max = [0xff; 8];
710        max[0] = 0x7f;
711        assert_eq!(Int64::MAX.to_be_bytes(), max);
712
713        let mut one = [0; 8];
714        one[7] = 1;
715        assert_eq!(Int64::from(1i64).to_be_bytes(), one);
716        // Python: `[b for b in (8535972485454015680).to_bytes(8, "big")]`
717        assert_eq!(
718            Int64::from(8535972485454015680i64).to_be_bytes(),
719            [118, 117, 221, 191, 255, 254, 172, 192]
720        );
721        assert_eq!(
722            Int64::from_be_bytes([17, 4, 23, 32, 87, 67, 123, 200]).to_be_bytes(),
723            [17, 4, 23, 32, 87, 67, 123, 200]
724        );
725    }
726
727    #[test]
728    fn int64_to_le_bytes_works() {
729        assert_eq!(Int64::zero().to_le_bytes(), [0; 8]);
730
731        let mut max = [0xff; 8];
732        max[7] = 0x7f;
733        assert_eq!(Int64::MAX.to_le_bytes(), max);
734
735        let mut one = [0; 8];
736        one[0] = 1;
737        assert_eq!(Int64::from(1i64).to_le_bytes(), one);
738        // Python: `[b for b in (8535972485454015680).to_bytes(8, "little")]`
739        assert_eq!(
740            Int64::from(8535972485454015680i64).to_le_bytes(),
741            [192, 172, 254, 255, 191, 221, 117, 118]
742        );
743        assert_eq!(
744            Int64::from_be_bytes([17, 4, 23, 32, 87, 67, 123, 200]).to_le_bytes(),
745            [200, 123, 67, 87, 32, 23, 4, 17]
746        );
747    }
748
749    #[test]
750    fn int64_is_zero_works() {
751        assert!(Int64::zero().is_zero());
752        assert!(Int64(i64::from(0u32)).is_zero());
753
754        assert!(!Int64::from(1u32).is_zero());
755        assert!(!Int64::from(123u32).is_zero());
756        assert!(!Int64::from(-123i32).is_zero());
757    }
758
759    #[test]
760    fn int64_is_negative_works() {
761        assert!(Int64::MIN.is_negative());
762        assert!(Int64::from(-123i32).is_negative());
763
764        assert!(!Int64::MAX.is_negative());
765        assert!(!Int64::zero().is_negative());
766        assert!(!Int64::from(123u32).is_negative());
767    }
768
769    #[test]
770    fn int64_wrapping_methods() {
771        // wrapping_add
772        assert_eq!(
773            Int64::from(2u32).wrapping_add(Int64::from(2u32)),
774            Int64::from(4u32)
775        ); // non-wrapping
776        assert_eq!(Int64::MAX.wrapping_add(Int64::from(1u32)), Int64::MIN); // wrapping
777
778        // wrapping_sub
779        assert_eq!(
780            Int64::from(7u32).wrapping_sub(Int64::from(5u32)),
781            Int64::from(2u32)
782        ); // non-wrapping
783        assert_eq!(Int64::MIN.wrapping_sub(Int64::from(1u32)), Int64::MAX); // wrapping
784
785        // wrapping_mul
786        assert_eq!(
787            Int64::from(3u32).wrapping_mul(Int64::from(2u32)),
788            Int64::from(6u32)
789        ); // non-wrapping
790        assert_eq!(
791            Int64::MAX.wrapping_mul(Int64::from(2u32)),
792            Int64::from(-2i32)
793        ); // wrapping
794
795        // wrapping_pow
796        assert_eq!(Int64::from(2u32).wrapping_pow(3), Int64::from(8u32)); // non-wrapping
797        assert_eq!(Int64::MAX.wrapping_pow(2), Int64::from(1u32)); // wrapping
798    }
799
800    #[test]
801    fn int64_json() {
802        let orig = Int64::from(1234567890987654321i64);
803        let serialized = serde_json::to_vec(&orig).unwrap();
804        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
805        let parsed: Int64 = serde_json::from_slice(&serialized).unwrap();
806        assert_eq!(parsed, orig);
807    }
808
809    #[test]
810    fn int64_compare() {
811        let a = Int64::from(12345u32);
812        let b = Int64::from(23456u32);
813
814        assert!(a < b);
815        assert!(b > a);
816        assert_eq!(a, Int64::from(12345u32));
817    }
818
819    #[test]
820    #[allow(clippy::op_ref)]
821    fn int64_math() {
822        let a = Int64::from(-12345i32);
823        let b = Int64::from(23456u32);
824
825        // test + with owned and reference right hand side
826        assert_eq!(a + b, Int64::from(11111u32));
827        assert_eq!(a + &b, Int64::from(11111u32));
828
829        // test - with owned and reference right hand side
830        assert_eq!(b - a, Int64::from(35801u32));
831        assert_eq!(b - &a, Int64::from(35801u32));
832
833        // test += with owned and reference right hand side
834        let mut c = Int64::from(300000u32);
835        c += b;
836        assert_eq!(c, Int64::from(323456u32));
837        let mut d = Int64::from(300000u32);
838        d += &b;
839        assert_eq!(d, Int64::from(323456u32));
840
841        // test -= with owned and reference right hand side
842        let mut c = Int64::from(300000u32);
843        c -= b;
844        assert_eq!(c, Int64::from(276544u32));
845        let mut d = Int64::from(300000u32);
846        d -= &b;
847        assert_eq!(d, Int64::from(276544u32));
848
849        // test - with negative result
850        assert_eq!(a - b, Int64::from(-35801i32));
851    }
852
853    #[test]
854    #[should_panic]
855    fn int64_add_overflow_panics() {
856        let _ = Int64::MAX + Int64::from(12u32);
857    }
858
859    #[test]
860    #[allow(clippy::op_ref)]
861    fn int64_sub_works() {
862        assert_eq!(Int64::from(2u32) - Int64::from(1u32), Int64::from(1u32));
863        assert_eq!(Int64::from(2u32) - Int64::from(0u32), Int64::from(2u32));
864        assert_eq!(Int64::from(2u32) - Int64::from(2u32), Int64::from(0u32));
865        assert_eq!(Int64::from(2u32) - Int64::from(3u32), Int64::from(-1i32));
866
867        // works for refs
868        let a = Int64::from(10u32);
869        let b = Int64::from(3u32);
870        let expected = Int64::from(7u32);
871        assert_eq!(a - b, expected);
872        assert_eq!(a - &b, expected);
873        assert_eq!(&a - b, expected);
874        assert_eq!(&a - &b, expected);
875    }
876
877    #[test]
878    #[should_panic]
879    fn int64_sub_overflow_panics() {
880        let _ = Int64::MIN + Int64::one() - Int64::from(2u32);
881    }
882
883    #[test]
884    fn int64_sub_assign_works() {
885        let mut a = Int64::from(14u32);
886        a -= Int64::from(2u32);
887        assert_eq!(a, Int64::from(12u32));
888
889        // works for refs
890        let mut a = Int64::from(10u32);
891        let b = Int64::from(3u32);
892        let expected = Int64::from(7u32);
893        a -= &b;
894        assert_eq!(a, expected);
895    }
896
897    #[test]
898    #[allow(clippy::op_ref)]
899    fn int64_mul_works() {
900        assert_eq!(Int64::from(2u32) * Int64::from(3u32), Int64::from(6u32));
901        assert_eq!(Int64::from(2u32) * Int64::zero(), Int64::zero());
902
903        // works for refs
904        let a = Int64::from(11u32);
905        let b = Int64::from(3u32);
906        let expected = Int64::from(33u32);
907        assert_eq!(a * b, expected);
908        assert_eq!(a * &b, expected);
909        assert_eq!(&a * b, expected);
910        assert_eq!(&a * &b, expected);
911    }
912
913    #[test]
914    fn int64_mul_assign_works() {
915        let mut a = Int64::from(14u32);
916        a *= Int64::from(2u32);
917        assert_eq!(a, Int64::from(28u32));
918
919        // works for refs
920        let mut a = Int64::from(10u32);
921        let b = Int64::from(3u32);
922        a *= &b;
923        assert_eq!(a, Int64::from(30u32));
924    }
925
926    #[test]
927    fn int64_pow_works() {
928        assert_eq!(Int64::from(2u32).pow(2), Int64::from(4u32));
929        assert_eq!(Int64::from(2u32).pow(10), Int64::from(1024u32));
930    }
931
932    #[test]
933    #[should_panic]
934    fn int64_pow_overflow_panics() {
935        _ = Int64::MAX.pow(2u32);
936    }
937
938    #[test]
939    fn int64_checked_multiply_ratio_works() {
940        let base = Int64(500);
941
942        // factor 1/1
943        assert_eq!(base.checked_multiply_ratio(1i64, 1i64).unwrap(), base);
944        assert_eq!(base.checked_multiply_ratio(3i64, 3i64).unwrap(), base);
945        assert_eq!(
946            base.checked_multiply_ratio(654321i64, 654321i64).unwrap(),
947            base
948        );
949        assert_eq!(
950            base.checked_multiply_ratio(i64::MAX, i64::MAX).unwrap(),
951            base
952        );
953
954        // factor 3/2
955        assert_eq!(base.checked_multiply_ratio(3i64, 2i64).unwrap(), Int64(750));
956        assert_eq!(
957            base.checked_multiply_ratio(333333i64, 222222i64).unwrap(),
958            Int64(750)
959        );
960
961        // factor 2/3 (integer division always floors the result)
962        assert_eq!(base.checked_multiply_ratio(2i64, 3i64).unwrap(), Int64(333));
963        assert_eq!(
964            base.checked_multiply_ratio(222222i64, 333333i64).unwrap(),
965            Int64(333)
966        );
967
968        // factor 5/6 (integer division always floors the result)
969        assert_eq!(base.checked_multiply_ratio(5i64, 6i64).unwrap(), Int64(416));
970        assert_eq!(
971            base.checked_multiply_ratio(100i64, 120i64).unwrap(),
972            Int64(416)
973        );
974    }
975
976    #[test]
977    fn int64_checked_multiply_ratio_does_not_panic() {
978        assert_eq!(
979            Int64(500i64).checked_multiply_ratio(1i64, 0i64),
980            Err(CheckedMultiplyRatioError::DivideByZero),
981        );
982        assert_eq!(
983            Int64(500i64).checked_multiply_ratio(i64::MAX, 1i64),
984            Err(CheckedMultiplyRatioError::Overflow),
985        );
986    }
987
988    #[test]
989    fn int64_shr_works() {
990        let original = Int64::from_be_bytes([0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8]);
991
992        let shifted = Int64::from_be_bytes([0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8]);
993
994        assert_eq!(original >> 2u32, shifted);
995    }
996
997    #[test]
998    #[should_panic]
999    fn int64_shr_overflow_panics() {
1000        let _ = Int64::from(1u32) >> 64u32;
1001    }
1002
1003    #[test]
1004    fn sum_works() {
1005        let nums = vec![
1006            Int64::from(17u32),
1007            Int64::from(123u32),
1008            Int64::from(540u32),
1009            Int64::from(82u32),
1010        ];
1011        let expected = Int64::from(762u32);
1012
1013        let sum_as_ref: Int64 = nums.iter().sum();
1014        assert_eq!(expected, sum_as_ref);
1015
1016        let sum_as_owned: Int64 = nums.into_iter().sum();
1017        assert_eq!(expected, sum_as_owned);
1018    }
1019
1020    #[test]
1021    fn int64_methods() {
1022        // checked_*
1023        assert!(matches!(
1024            Int64::MAX.checked_add(Int64::from(1u32)),
1025            Err(OverflowError { .. })
1026        ));
1027        assert_eq!(
1028            Int64::from(1u32).checked_add(Int64::from(1u32)),
1029            Ok(Int64::from(2u32)),
1030        );
1031        assert!(matches!(
1032            Int64::MIN.checked_sub(Int64::from(1u32)),
1033            Err(OverflowError { .. })
1034        ));
1035        assert_eq!(
1036            Int64::from(2u32).checked_sub(Int64::from(1u32)),
1037            Ok(Int64::from(1u32)),
1038        );
1039        assert!(matches!(
1040            Int64::MAX.checked_mul(Int64::from(2u32)),
1041            Err(OverflowError { .. })
1042        ));
1043        assert_eq!(
1044            Int64::from(2u32).checked_mul(Int64::from(2u32)),
1045            Ok(Int64::from(4u32)),
1046        );
1047        assert!(matches!(
1048            Int64::MAX.checked_pow(2u32),
1049            Err(OverflowError { .. })
1050        ));
1051        assert_eq!(Int64::from(2u32).checked_pow(3u32), Ok(Int64::from(8u32)),);
1052        assert_eq!(
1053            Int64::MAX.checked_div(Int64::from(0u32)),
1054            Err(DivisionError::DivideByZero)
1055        );
1056        assert_eq!(
1057            Int64::from(6u32).checked_div(Int64::from(2u32)),
1058            Ok(Int64::from(3u32)),
1059        );
1060        assert_eq!(
1061            Int64::MAX.checked_div_euclid(Int64::from(0u32)),
1062            Err(DivisionError::DivideByZero)
1063        );
1064        assert_eq!(
1065            Int64::from(6u32).checked_div_euclid(Int64::from(2u32)),
1066            Ok(Int64::from(3u32)),
1067        );
1068        assert_eq!(
1069            Int64::from(7u32).checked_div_euclid(Int64::from(2u32)),
1070            Ok(Int64::from(3u32)),
1071        );
1072        assert!(matches!(
1073            Int64::MAX.checked_rem(Int64::from(0u32)),
1074            Err(DivideByZeroError { .. })
1075        ));
1076        // checked_* with negative numbers
1077        assert_eq!(
1078            Int64::from(-12i32).checked_div(Int64::from(10i32)),
1079            Ok(Int64::from(-1i32)),
1080        );
1081        assert_eq!(Int64::from(-2i32).checked_pow(3u32), Ok(Int64::from(-8i32)),);
1082        assert_eq!(
1083            Int64::from(-6i32).checked_mul(Int64::from(-7i32)),
1084            Ok(Int64::from(42i32)),
1085        );
1086        assert_eq!(
1087            Int64::from(-2i32).checked_add(Int64::from(3i32)),
1088            Ok(Int64::from(1i32)),
1089        );
1090        assert_eq!(
1091            Int64::from(-1i32).checked_div_euclid(Int64::from(-2i32)),
1092            Ok(Int64::from(1u32)),
1093        );
1094
1095        // saturating_*
1096        assert_eq!(Int64::MAX.saturating_add(Int64::from(1u32)), Int64::MAX);
1097        assert_eq!(Int64::MIN.saturating_sub(Int64::from(1u32)), Int64::MIN);
1098        assert_eq!(Int64::MAX.saturating_mul(Int64::from(2u32)), Int64::MAX);
1099        assert_eq!(Int64::from(4u32).saturating_pow(2u32), Int64::from(16u32));
1100        assert_eq!(Int64::MAX.saturating_pow(2u32), Int64::MAX);
1101    }
1102
1103    #[test]
1104    #[allow(clippy::op_ref)]
1105    fn int64_implements_rem() {
1106        let a = Int64::from(10u32);
1107        assert_eq!(a % Int64::from(10u32), Int64::zero());
1108        assert_eq!(a % Int64::from(2u32), Int64::zero());
1109        assert_eq!(a % Int64::from(1u32), Int64::zero());
1110        assert_eq!(a % Int64::from(3u32), Int64::from(1u32));
1111        assert_eq!(a % Int64::from(4u32), Int64::from(2u32));
1112
1113        assert_eq!(Int64::from(-12i32) % Int64::from(10i32), Int64::from(-2i32));
1114        assert_eq!(Int64::from(12i32) % Int64::from(-10i32), Int64::from(2i32));
1115        assert_eq!(
1116            Int64::from(-12i32) % Int64::from(-10i32),
1117            Int64::from(-2i32)
1118        );
1119
1120        // works for refs
1121        let a = Int64::from(10u32);
1122        let b = Int64::from(3u32);
1123        let expected = Int64::from(1u32);
1124        assert_eq!(a % b, expected);
1125        assert_eq!(a % &b, expected);
1126        assert_eq!(&a % b, expected);
1127        assert_eq!(&a % &b, expected);
1128    }
1129
1130    #[test]
1131    #[should_panic(expected = "divisor of zero")]
1132    fn int64_rem_panics_for_zero() {
1133        let _ = Int64::from(10u32) % Int64::zero();
1134    }
1135
1136    #[test]
1137    fn int64_rem_assign_works() {
1138        let mut a = Int64::from(30u32);
1139        a %= Int64::from(4u32);
1140        assert_eq!(a, Int64::from(2u32));
1141
1142        // works for refs
1143        let mut a = Int64::from(25u32);
1144        let b = Int64::from(6u32);
1145        a %= &b;
1146        assert_eq!(a, Int64::from(1u32));
1147    }
1148
1149    #[test]
1150    fn int64_shr() {
1151        let x: Int64 = 0x4000_0000_0000_0000i64.into();
1152        assert_eq!(x >> 0, x); // right shift by 0 should be no-op
1153        assert_eq!(x >> 1, Int64::from(0x2000_0000_0000_0000i64));
1154        assert_eq!(x >> 4, Int64::from(0x0400_0000_0000_0000i64));
1155        // right shift of MIN value by the maximum shift value should result in -1 (filled with 1s)
1156        assert_eq!(
1157            Int64::MIN >> (core::mem::size_of::<Int64>() as u32 * 8 - 1),
1158            -Int64::one()
1159        );
1160    }
1161
1162    #[test]
1163    fn int64_shl() {
1164        let x: Int64 = 0x0800_0000_0000_0000i64.into();
1165        assert_eq!(x << 0, x); // left shift by 0 should be no-op
1166        assert_eq!(x << 1, Int64::from(0x1000_0000_0000_0000i64));
1167        assert_eq!(x << 4, Int64::from(0x0800_0000_0000_0000i64 << 4));
1168        // left shift by by the maximum shift value should result in MIN
1169        assert_eq!(
1170            Int64::one() << (core::mem::size_of::<Int64>() as u32 * 8 - 1),
1171            Int64::MIN
1172        );
1173    }
1174
1175    #[test]
1176    fn int64_abs_diff_works() {
1177        let a = Int64::from(42u32);
1178        let b = Int64::from(5u32);
1179        let expected = Uint64::from(37u32);
1180        assert_eq!(a.abs_diff(b), expected);
1181        assert_eq!(b.abs_diff(a), expected);
1182
1183        let c = Int64::from(-5i32);
1184        assert_eq!(b.abs_diff(c), Uint64::from(10u32));
1185        assert_eq!(c.abs_diff(b), Uint64::from(10u32));
1186    }
1187
1188    #[test]
1189    fn int64_abs_works() {
1190        let a = Int64::from(42i32);
1191        assert_eq!(a.abs(), a);
1192
1193        let b = Int64::from(-42i32);
1194        assert_eq!(b.abs(), a);
1195
1196        assert_eq!(Int64::zero().abs(), Int64::zero());
1197        assert_eq!((Int64::MIN + Int64::one()).abs(), Int64::MAX);
1198    }
1199
1200    #[test]
1201    fn int64_unsigned_abs_works() {
1202        assert_eq!(Int64::zero().unsigned_abs(), Uint64::zero());
1203        assert_eq!(Int64::one().unsigned_abs(), Uint64::one());
1204        assert_eq!(
1205            Int64::MIN.unsigned_abs(),
1206            Uint64::new(Int64::MAX.0 as u64) + Uint64::one()
1207        );
1208
1209        let v = Int64::from(-42i32);
1210        assert_eq!(v.unsigned_abs(), v.abs_diff(Int64::zero()));
1211    }
1212
1213    #[test]
1214    #[should_panic = "attempt to calculate absolute value with overflow"]
1215    fn int64_abs_min_panics() {
1216        _ = Int64::MIN.abs();
1217    }
1218
1219    #[test]
1220    #[should_panic = "attempt to negate with overflow"]
1221    fn int64_neg_min_panics() {
1222        _ = -Int64::MIN;
1223    }
1224
1225    #[test]
1226    fn int64_partial_eq() {
1227        let test_cases = [(1, 1, true), (42, 42, true), (42, 24, false), (0, 0, true)]
1228            .into_iter()
1229            .map(|(lhs, rhs, expected): (i64, i64, bool)| {
1230                (Int64::from(lhs), Int64::from(rhs), expected)
1231            });
1232
1233        #[allow(clippy::op_ref)]
1234        for (lhs, rhs, expected) in test_cases {
1235            assert_eq!(lhs == rhs, expected);
1236            assert_eq!(&lhs == rhs, expected);
1237            assert_eq!(lhs == &rhs, expected);
1238            assert_eq!(&lhs == &rhs, expected);
1239        }
1240    }
1241}