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