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