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