cosmwasm_std/math/
uint64.rs

1use alloc::string::{String, ToString};
2use core::fmt;
3use core::ops::{
4    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr,
5    ShrAssign, Sub, SubAssign,
6};
7
8use crate::errors::{
9    CheckedMultiplyFractionError, CheckedMultiplyRatioError, DivideByZeroError, ErrorKind,
10    OverflowError, OverflowOperation, StdError,
11};
12use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
13use crate::{
14    __internal::forward_ref_partial_eq, impl_mul_fraction, Fraction, Int128, Int256, Int512, Int64,
15    Uint128,
16};
17
18use super::conversion::{
19    forward_try_from, from_and_to_bytes, primitive_to_wrapped_int, wrapped_int_to_primitive,
20};
21use super::impl_int_serde;
22use super::num_consts::NumConsts;
23
24/// A thin wrapper around u64 that is using strings for JSON encoding/decoding,
25/// such that the full u64 range can be used for clients that convert JSON numbers to floats,
26/// like JavaScript and jq.
27///
28/// # Examples
29///
30/// Use `from` to create instances of this and `u64` to get the value out:
31///
32/// ```
33/// # use cosmwasm_std::Uint64;
34/// let a = Uint64::from(42u64);
35/// assert_eq!(a.u64(), 42);
36///
37/// let b = Uint64::from(70u32);
38/// assert_eq!(b.u64(), 70);
39/// ```
40#[derive(
41    Copy,
42    Clone,
43    Default,
44    Debug,
45    PartialEq,
46    Eq,
47    PartialOrd,
48    Ord,
49    schemars::JsonSchema,
50    cw_schema::Schemaifier,
51)]
52#[schemaifier(type = cw_schema::NodeType::Integer { precision: 64, signed: false })]
53pub struct Uint64(#[schemars(with = "String")] pub(crate) u64);
54
55impl_int_serde!(Uint64);
56forward_ref_partial_eq!(Uint64, Uint64);
57
58impl Uint64 {
59    pub const MAX: Self = Self(u64::MAX);
60    pub const MIN: Self = Self(u64::MIN);
61
62    /// Creates a Uint64(value).
63    ///
64    /// This method is less flexible than `from` but can be called in a const context.
65    #[inline]
66    #[must_use]
67    pub const fn new(value: u64) -> Self {
68        Uint64(value)
69    }
70
71    /// Creates a Uint64(0)
72    #[inline]
73    pub const fn zero() -> Self {
74        Uint64(0)
75    }
76
77    /// Creates a Uint64(1)
78    #[inline]
79    pub const fn one() -> Self {
80        Self(1)
81    }
82
83    /// Returns a copy of the internal data
84    pub const fn u64(&self) -> u64 {
85        self.0
86    }
87
88    from_and_to_bytes!(u64, 8);
89
90    #[must_use]
91    pub const fn is_zero(&self) -> bool {
92        self.0 == 0
93    }
94
95    #[must_use = "this returns the result of the operation, without modifying the original"]
96    pub const fn pow(self, exp: u32) -> Self {
97        match self.0.checked_pow(exp) {
98            Some(val) => Self(val),
99            None => panic!("attempt to exponentiate with overflow"),
100        }
101    }
102
103    /// Returns the base 2 logarithm of the number, rounded down.
104    ///
105    /// # Panics
106    ///
107    /// This function will panic if `self` is zero.
108    #[must_use = "this returns the result of the operation, without modifying the original"]
109    pub fn ilog2(self) -> u32 {
110        self.0.checked_ilog2().unwrap()
111    }
112
113    /// Returns `self * numerator / denominator`.
114    ///
115    /// Due to the nature of the integer division involved, the result is always floored.
116    /// E.g. 5 * 99/100 = 4.
117    #[must_use = "this returns the result of the operation, without modifying the original"]
118    pub fn multiply_ratio<A: Into<u64>, B: Into<u64>>(
119        &self,
120        numerator: A,
121        denominator: B,
122    ) -> Uint64 {
123        match self.checked_multiply_ratio(numerator, denominator) {
124            Ok(value) => value,
125            Err(CheckedMultiplyRatioError::DivideByZero) => {
126                panic!("Denominator must not be zero")
127            }
128            Err(CheckedMultiplyRatioError::Overflow) => panic!("Multiplication overflow"),
129        }
130    }
131
132    /// Returns `self * numerator / denominator`.
133    ///
134    /// Due to the nature of the integer division involved, the result is always floored.
135    /// E.g. 5 * 99/100 = 4.
136    pub fn checked_multiply_ratio<A: Into<u64>, B: Into<u64>>(
137        &self,
138        numerator: A,
139        denominator: B,
140    ) -> Result<Uint64, CheckedMultiplyRatioError> {
141        let numerator = numerator.into();
142        let denominator = denominator.into();
143        if denominator == 0 {
144            return Err(CheckedMultiplyRatioError::DivideByZero);
145        }
146        match (self.full_mul(numerator) / Uint128::from(denominator)).try_into() {
147            Ok(ratio) => Ok(ratio),
148            Err(_) => Err(CheckedMultiplyRatioError::Overflow),
149        }
150    }
151
152    /// Multiplies two `Uint64`/`u64` values without overflow, producing an
153    /// [`Uint128`].
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use cosmwasm_std::Uint64;
159    ///
160    /// let a = Uint64::MAX;
161    /// let result = a.full_mul(2u32);
162    /// assert_eq!(result.to_string(), "36893488147419103230");
163    /// ```
164    #[must_use = "this returns the result of the operation, without modifying the original"]
165    pub fn full_mul(self, rhs: impl Into<Self>) -> Uint128 {
166        Uint128::from(self)
167            .checked_mul(Uint128::from(rhs.into()))
168            .unwrap()
169    }
170
171    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
172        self.0
173            .checked_add(other.0)
174            .map(Self)
175            .ok_or_else(|| OverflowError::new(OverflowOperation::Add))
176    }
177
178    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
179        self.0
180            .checked_sub(other.0)
181            .map(Self)
182            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub))
183    }
184
185    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
186        self.0
187            .checked_mul(other.0)
188            .map(Self)
189            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul))
190    }
191
192    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
193        self.0
194            .checked_pow(exp)
195            .map(Self)
196            .ok_or_else(|| OverflowError::new(OverflowOperation::Pow))
197    }
198
199    pub fn checked_div(self, other: Self) -> Result<Self, DivideByZeroError> {
200        self.0
201            .checked_div(other.0)
202            .map(Self)
203            .ok_or(DivideByZeroError)
204    }
205
206    pub fn checked_div_euclid(self, other: Self) -> Result<Self, DivideByZeroError> {
207        self.0
208            .checked_div_euclid(other.0)
209            .map(Self)
210            .ok_or(DivideByZeroError)
211    }
212
213    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
214        self.0
215            .checked_rem(other.0)
216            .map(Self)
217            .ok_or(DivideByZeroError)
218    }
219
220    pub fn checked_shr(self, other: u32) -> Result<Self, OverflowError> {
221        if other >= 64 {
222            return Err(OverflowError::new(OverflowOperation::Shr));
223        }
224
225        Ok(Self(self.0.shr(other)))
226    }
227
228    pub fn checked_shl(self, other: u32) -> Result<Self, OverflowError> {
229        if other >= 64 {
230            return Err(OverflowError::new(OverflowOperation::Shl));
231        }
232
233        Ok(Self(self.0.shl(other)))
234    }
235
236    #[must_use = "this returns the result of the operation, without modifying the original"]
237    #[inline]
238    pub fn wrapping_add(self, other: Self) -> Self {
239        Self(self.0.wrapping_add(other.0))
240    }
241
242    #[must_use = "this returns the result of the operation, without modifying the original"]
243    #[inline]
244    pub fn wrapping_sub(self, other: Self) -> Self {
245        Self(self.0.wrapping_sub(other.0))
246    }
247
248    #[must_use = "this returns the result of the operation, without modifying the original"]
249    #[inline]
250    pub fn wrapping_mul(self, other: Self) -> Self {
251        Self(self.0.wrapping_mul(other.0))
252    }
253
254    #[must_use = "this returns the result of the operation, without modifying the original"]
255    #[inline]
256    pub fn wrapping_pow(self, other: u32) -> Self {
257        Self(self.0.wrapping_pow(other))
258    }
259
260    #[must_use = "this returns the result of the operation, without modifying the original"]
261    pub fn saturating_add(self, other: Self) -> Self {
262        Self(self.0.saturating_add(other.0))
263    }
264
265    #[must_use = "this returns the result of the operation, without modifying the original"]
266    pub fn saturating_sub(self, other: Self) -> Self {
267        Self(self.0.saturating_sub(other.0))
268    }
269
270    #[must_use = "this returns the result of the operation, without modifying the original"]
271    pub fn saturating_mul(self, other: Self) -> Self {
272        Self(self.0.saturating_mul(other.0))
273    }
274
275    #[must_use = "this returns the result of the operation, without modifying the original"]
276    pub fn saturating_pow(self, exp: u32) -> Self {
277        Self(self.0.saturating_pow(exp))
278    }
279
280    /// Strict integer addition. Computes `self + rhs`, panicking if overflow occurred.
281    ///
282    /// This is the same as [`Uint64::add`] but const.
283    #[must_use = "this returns the result of the operation, without modifying the original"]
284    pub const fn strict_add(self, rhs: Self) -> Self {
285        match self.0.checked_add(rhs.u64()) {
286            None => panic!("attempt to add with overflow"),
287            Some(sum) => Self(sum),
288        }
289    }
290
291    /// Strict integer subtraction. Computes `self - rhs`, panicking if overflow occurred.
292    ///
293    /// This is the same as [`Uint64::sub`] but const.
294    #[must_use = "this returns the result of the operation, without modifying the original"]
295    pub const fn strict_sub(self, other: Self) -> Self {
296        match self.0.checked_sub(other.u64()) {
297            None => panic!("attempt to subtract with overflow"),
298            Some(diff) => Self(diff),
299        }
300    }
301
302    #[must_use = "this returns the result of the operation, without modifying the original"]
303    pub const fn abs_diff(self, other: Self) -> Self {
304        Self(if self.0 < other.0 {
305            other.0 - self.0
306        } else {
307            self.0 - other.0
308        })
309    }
310}
311
312impl NumConsts for Uint64 {
313    const ZERO: Self = Self::zero();
314    const ONE: Self = Self::one();
315    const MAX: Self = Self::MAX;
316    const MIN: Self = Self::MIN;
317}
318
319impl_mul_fraction!(Uint64);
320
321// `From<u{128,64,32,16,8}>` is implemented manually instead of
322// using `impl<T: Into<u64>> From<T> for Uint64` because
323// of the conflict with `TryFrom<&str>` as described here
324// https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error
325
326// uint to Uint
327primitive_to_wrapped_int!(u8, Uint64);
328primitive_to_wrapped_int!(u16, Uint64);
329primitive_to_wrapped_int!(u32, Uint64);
330primitive_to_wrapped_int!(u64, Uint64);
331
332// Uint to uint
333wrapped_int_to_primitive!(Uint64, u64);
334wrapped_int_to_primitive!(Uint64, u128);
335
336// Int to Uint
337forward_try_from!(Int64, Uint64);
338forward_try_from!(Int128, Uint64);
339forward_try_from!(Int256, Uint64);
340forward_try_from!(Int512, Uint64);
341
342impl TryFrom<&str> for Uint64 {
343    type Error = StdError;
344
345    fn try_from(val: &str) -> Result<Self, Self::Error> {
346        match val.parse::<u64>() {
347            Ok(u) => Ok(Uint64(u)),
348            Err(e) => {
349                Err(StdError::msg(format_args!("Parsing u64: {e}")).with_kind(ErrorKind::Parsing))
350            }
351        }
352    }
353}
354
355impl From<Uint64> for String {
356    fn from(original: Uint64) -> Self {
357        original.to_string()
358    }
359}
360
361impl fmt::Display for Uint64 {
362    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363        self.0.fmt(f)
364    }
365}
366
367impl Add<Uint64> for Uint64 {
368    type Output = Self;
369
370    fn add(self, rhs: Self) -> Self {
371        self.strict_add(rhs)
372    }
373}
374forward_ref_binop!(impl Add, add for Uint64, Uint64);
375
376impl Sub<Uint64> for Uint64 {
377    type Output = Self;
378
379    fn sub(self, rhs: Self) -> Self {
380        self.strict_sub(rhs)
381    }
382}
383forward_ref_binop!(impl Sub, sub for Uint64, Uint64);
384
385impl SubAssign<Uint64> for Uint64 {
386    fn sub_assign(&mut self, rhs: Uint64) {
387        *self = *self - rhs;
388    }
389}
390forward_ref_op_assign!(impl SubAssign, sub_assign for Uint64, Uint64);
391
392impl Mul<Uint64> for Uint64 {
393    type Output = Self;
394
395    fn mul(self, rhs: Self) -> Self::Output {
396        Self(
397            self.u64()
398                .checked_mul(rhs.u64())
399                .expect("attempt to multiply with overflow"),
400        )
401    }
402}
403forward_ref_binop!(impl Mul, mul for Uint64, Uint64);
404
405impl MulAssign<Uint64> for Uint64 {
406    fn mul_assign(&mut self, rhs: Self) {
407        *self = *self * rhs;
408    }
409}
410forward_ref_op_assign!(impl MulAssign, mul_assign for Uint64, Uint64);
411
412impl Div<Uint64> for Uint64 {
413    type Output = Self;
414
415    fn div(self, rhs: Self) -> Self::Output {
416        Self(self.u64().checked_div(rhs.u64()).unwrap())
417    }
418}
419
420impl<'a> Div<&'a Uint64> for Uint64 {
421    type Output = Self;
422
423    fn div(self, rhs: &'a Uint64) -> Self::Output {
424        Self(self.u64().checked_div(rhs.u64()).unwrap())
425    }
426}
427
428impl Rem for Uint64 {
429    type Output = Self;
430
431    /// # Panics
432    ///
433    /// This operation will panic if `rhs` is zero.
434    #[inline]
435    fn rem(self, rhs: Self) -> Self {
436        Self(self.0.rem(rhs.0))
437    }
438}
439forward_ref_binop!(impl Rem, rem for Uint64, Uint64);
440
441impl Not for Uint64 {
442    type Output = Self;
443
444    fn not(self) -> Self::Output {
445        Self(!self.0)
446    }
447}
448
449impl RemAssign<Uint64> for Uint64 {
450    fn rem_assign(&mut self, rhs: Uint64) {
451        *self = *self % rhs;
452    }
453}
454forward_ref_op_assign!(impl RemAssign, rem_assign for Uint64, Uint64);
455
456impl Shr<u32> for Uint64 {
457    type Output = Self;
458
459    fn shr(self, rhs: u32) -> Self::Output {
460        Self(self.u64().checked_shr(rhs).unwrap())
461    }
462}
463
464impl<'a> Shr<&'a u32> for Uint64 {
465    type Output = Self;
466
467    fn shr(self, rhs: &'a u32) -> Self::Output {
468        Self(self.u64().checked_shr(*rhs).unwrap())
469    }
470}
471
472impl Shl<u32> for Uint64 {
473    type Output = Self;
474
475    fn shl(self, rhs: u32) -> Self::Output {
476        Self(
477            self.u64()
478                .checked_shl(rhs)
479                .expect("attempt to shift left with overflow"),
480        )
481    }
482}
483
484impl<'a> Shl<&'a u32> for Uint64 {
485    type Output = Self;
486
487    fn shl(self, rhs: &'a u32) -> Self::Output {
488        self.shl(*rhs)
489    }
490}
491
492impl AddAssign<Uint64> for Uint64 {
493    fn add_assign(&mut self, rhs: Uint64) {
494        self.0 = self.0.checked_add(rhs.u64()).unwrap();
495    }
496}
497
498impl<'a> AddAssign<&'a Uint64> for Uint64 {
499    fn add_assign(&mut self, rhs: &'a Uint64) {
500        self.0 = self.0.checked_add(rhs.u64()).unwrap();
501    }
502}
503
504impl DivAssign<Uint64> for Uint64 {
505    fn div_assign(&mut self, rhs: Self) {
506        self.0 = self.0.checked_div(rhs.u64()).unwrap();
507    }
508}
509
510impl<'a> DivAssign<&'a Uint64> for Uint64 {
511    fn div_assign(&mut self, rhs: &'a Uint64) {
512        self.0 = self.0.checked_div(rhs.u64()).unwrap();
513    }
514}
515
516impl ShrAssign<u32> for Uint64 {
517    fn shr_assign(&mut self, rhs: u32) {
518        self.0 = self.0.checked_shr(rhs).unwrap();
519    }
520}
521
522impl<'a> ShrAssign<&'a u32> for Uint64 {
523    fn shr_assign(&mut self, rhs: &'a u32) {
524        self.0 = self.0.checked_shr(*rhs).unwrap();
525    }
526}
527
528impl ShlAssign<u32> for Uint64 {
529    fn shl_assign(&mut self, rhs: u32) {
530        *self = self.shl(rhs);
531    }
532}
533
534impl<'a> ShlAssign<&'a u32> for Uint64 {
535    fn shl_assign(&mut self, rhs: &'a u32) {
536        *self = self.shl(*rhs);
537    }
538}
539
540impl<A> core::iter::Sum<A> for Uint64
541where
542    Self: Add<A, Output = Self>,
543{
544    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
545        iter.fold(Self::zero(), Add::add)
546    }
547}
548
549#[cfg(test)]
550mod tests {
551    use super::*;
552    use crate::errors::CheckedMultiplyFractionError::{ConversionOverflow, DivideByZero};
553    use crate::math::conversion::test_try_from_int_to_uint;
554    use crate::ConversionOverflowError;
555
556    use alloc::string::ToString;
557
558    #[test]
559    fn size_of_works() {
560        assert_eq!(core::mem::size_of::<Uint64>(), 8);
561    }
562
563    #[test]
564    fn uint64_not_works() {
565        assert_eq!(!Uint64::new(1234806), Uint64::new(!1234806));
566
567        assert_eq!(!Uint64::MAX, Uint64::new(!u64::MAX));
568        assert_eq!(!Uint64::MIN, Uint64::new(!u64::MIN));
569    }
570
571    #[test]
572    fn uint64_zero_works() {
573        let zero = Uint64::zero();
574        assert_eq!(zero.to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
575    }
576
577    #[test]
578    fn uint64_one_works() {
579        let one = Uint64::one();
580        assert_eq!(one.to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 1]);
581    }
582
583    #[test]
584    fn uint64_from_be_bytes_works() {
585        // zero
586        let original = [0; 8];
587        let num = Uint64::from_be_bytes(original);
588        assert!(num.is_zero());
589
590        // one
591        let original = [0, 0, 0, 0, 0, 0, 0, 1];
592        let num = Uint64::from_be_bytes(original);
593        assert_eq!(num.u64(), 1);
594
595        // 258
596        let original = [0, 0, 0, 0, 0, 0, 1, 2];
597        let num = Uint64::from_be_bytes(original);
598        assert_eq!(num.u64(), 258);
599
600        // 2x roundtrip
601        let original = [1; 8];
602        let num = Uint64::from_be_bytes(original);
603        let a: [u8; 8] = num.to_be_bytes();
604        assert_eq!(a, original);
605
606        let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
607        let num = Uint64::from_be_bytes(original);
608        let resulting_bytes: [u8; 8] = num.to_be_bytes();
609        assert_eq!(resulting_bytes, original);
610    }
611
612    #[test]
613    fn uint64_from_le_bytes_works() {
614        // zero
615        let original = [0; 8];
616        let num = Uint64::from_le_bytes(original);
617        assert!(num.is_zero());
618
619        // one
620        let original = [1, 0, 0, 0, 0, 0, 0, 0];
621        let num = Uint64::from_le_bytes(original);
622        assert_eq!(num.u64(), 1);
623
624        // 258
625        let original = [2, 1, 0, 0, 0, 0, 0, 0];
626        let num = Uint64::from_le_bytes(original);
627        assert_eq!(num.u64(), 258);
628
629        // 2x roundtrip
630        let original = [1; 8];
631        let num = Uint64::from_le_bytes(original);
632        let a: [u8; 8] = num.to_le_bytes();
633        assert_eq!(a, original);
634
635        let original = [0u8, 222u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8];
636        let num = Uint64::from_le_bytes(original);
637        let resulting_bytes: [u8; 8] = num.to_le_bytes();
638        assert_eq!(resulting_bytes, original);
639    }
640
641    #[test]
642    fn uint64_convert_into() {
643        let original = Uint64(12345);
644        let a = u64::from(original);
645        assert_eq!(a, 12345);
646
647        let original = Uint64(12345);
648        let a = u128::from(original);
649        assert_eq!(a, 12345);
650
651        let original = Uint64(12345);
652        let a = String::from(original);
653        assert_eq!(a, "12345");
654    }
655
656    #[test]
657    fn uint64_convert_from() {
658        let a = Uint64::from(5u64);
659        assert_eq!(a.0, 5);
660
661        let a = Uint64::from(5u32);
662        assert_eq!(a.0, 5);
663
664        let a = Uint64::from(5u16);
665        assert_eq!(a.0, 5);
666
667        let a = Uint64::from(5u8);
668        assert_eq!(a.0, 5);
669
670        let result = Uint64::try_from("34567");
671        assert_eq!(result.unwrap().0, 34567);
672
673        let result = Uint64::try_from("1.23");
674        assert!(result.is_err());
675    }
676
677    #[test]
678    fn uint64_try_from_signed_works() {
679        test_try_from_int_to_uint::<Int64, Uint64>("Int64", "Uint64");
680        test_try_from_int_to_uint::<Int128, Uint64>("Int128", "Uint64");
681        test_try_from_int_to_uint::<Int256, Uint64>("Int256", "Uint64");
682        test_try_from_int_to_uint::<Int512, Uint64>("Int512", "Uint64");
683    }
684
685    #[test]
686    fn uint64_implements_display() {
687        let a = Uint64(12345);
688        assert_eq!(format!("Embedded: {a}"), "Embedded: 12345");
689        assert_eq!(a.to_string(), "12345");
690
691        let a = Uint64(0);
692        assert_eq!(format!("Embedded: {a}"), "Embedded: 0");
693        assert_eq!(a.to_string(), "0");
694    }
695
696    #[test]
697    fn uint64_display_padding_works() {
698        // width > natural representation
699        let a = Uint64::from(123u64);
700        assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
701
702        // width < natural representation
703        let a = Uint64::from(123u64);
704        assert_eq!(format!("Embedded: {a:02}"), "Embedded: 123");
705    }
706
707    #[test]
708    fn uint64_to_be_bytes_works() {
709        assert_eq!(Uint64::zero().to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
710        assert_eq!(
711            Uint64::MAX.to_be_bytes(),
712            [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
713        );
714        assert_eq!(Uint64::new(1).to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 1]);
715        // Python: `[b for b in (63374607431768124608).to_bytes(8, "big")]`
716        assert_eq!(
717            Uint64::new(874607431768124608).to_be_bytes(),
718            [12, 35, 58, 211, 72, 116, 172, 192]
719        );
720    }
721
722    #[test]
723    fn uint64_to_le_bytes_works() {
724        assert_eq!(Uint64::zero().to_le_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
725        assert_eq!(
726            Uint64::MAX.to_le_bytes(),
727            [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
728        );
729        assert_eq!(Uint64::new(1).to_le_bytes(), [1, 0, 0, 0, 0, 0, 0, 0]);
730        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(16, "little")]`
731        assert_eq!(
732            Uint64::new(874607431768124608).to_le_bytes(),
733            [192, 172, 116, 72, 211, 58, 35, 12]
734        );
735    }
736
737    #[test]
738    fn uint64_is_zero_works() {
739        assert!(Uint64::zero().is_zero());
740        assert!(Uint64(0).is_zero());
741
742        assert!(!Uint64(1).is_zero());
743        assert!(!Uint64(123).is_zero());
744    }
745
746    #[test]
747    fn uint64_json() {
748        let orig = Uint64(1234567890987654321);
749        let serialized = serde_json::to_vec(&orig).unwrap();
750        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
751        let parsed: Uint64 = serde_json::from_slice(&serialized).unwrap();
752        assert_eq!(parsed, orig);
753    }
754
755    #[test]
756    fn uint64_compare() {
757        let a = Uint64(12345);
758        let b = Uint64(23456);
759
760        assert!(a < b);
761        assert!(b > a);
762        assert_eq!(a, Uint64(12345));
763    }
764
765    #[test]
766    #[allow(clippy::op_ref)]
767    fn uint64_math() {
768        let a = Uint64(12345);
769        let b = Uint64(23456);
770
771        // test - with owned and reference right hand side
772        assert_eq!((b.checked_sub(a)).unwrap(), Uint64(11111));
773
774        // test += with owned and reference right hand side
775        let mut c = Uint64(300000);
776        c += b;
777        assert_eq!(c, Uint64(323456));
778        let mut d = Uint64(300000);
779        d += &b;
780        assert_eq!(d, Uint64(323456));
781
782        // error result on underflow (- would produce negative result)
783        let underflow_result = a.checked_sub(b);
784        let OverflowError { operation } = underflow_result.unwrap_err();
785        assert_eq!(operation, OverflowOperation::Sub);
786    }
787
788    #[test]
789    #[allow(clippy::op_ref)]
790    fn uint64_add_works() {
791        assert_eq!(Uint64::from(2u32) + Uint64::from(1u32), Uint64::from(3u32));
792        assert_eq!(Uint64::from(2u32) + Uint64::from(0u32), Uint64::from(2u32));
793
794        // works for refs
795        let a = Uint64::from(10u32);
796        let b = Uint64::from(3u32);
797        let expected = Uint64::from(13u32);
798        assert_eq!(a + b, expected);
799        assert_eq!(a + &b, expected);
800        assert_eq!(&a + b, expected);
801        assert_eq!(&a + &b, expected);
802    }
803
804    #[test]
805    #[should_panic(expected = "attempt to add with overflow")]
806    fn uint64_add_overflow_panics() {
807        let max = Uint64::MAX;
808        let _ = max + Uint64(12);
809    }
810
811    #[test]
812    #[allow(clippy::op_ref)]
813    fn uint64_sub_works() {
814        assert_eq!(Uint64(2) - Uint64(1), Uint64(1));
815        assert_eq!(Uint64(2) - Uint64(0), Uint64(2));
816        assert_eq!(Uint64(2) - Uint64(2), Uint64(0));
817
818        // works for refs
819        let a = Uint64::new(10);
820        let b = Uint64::new(3);
821        let expected = Uint64::new(7);
822        assert_eq!(a - b, expected);
823        assert_eq!(a - &b, expected);
824        assert_eq!(&a - b, expected);
825        assert_eq!(&a - &b, expected);
826    }
827
828    #[test]
829    #[should_panic]
830    fn uint64_sub_overflow_panics() {
831        let _ = Uint64(1) - Uint64(2);
832    }
833
834    #[test]
835    fn uint64_sub_assign_works() {
836        let mut a = Uint64(14);
837        a -= Uint64(2);
838        assert_eq!(a, Uint64(12));
839
840        // works for refs
841        let mut a = Uint64::new(10);
842        let b = Uint64::new(3);
843        let expected = Uint64::new(7);
844        a -= &b;
845        assert_eq!(a, expected);
846    }
847
848    #[test]
849    #[allow(clippy::op_ref)]
850    fn uint64_mul_works() {
851        assert_eq!(Uint64::from(2u32) * Uint64::from(3u32), Uint64::from(6u32));
852        assert_eq!(Uint64::from(2u32) * Uint64::zero(), Uint64::zero());
853
854        // works for refs
855        let a = Uint64::from(11u32);
856        let b = Uint64::from(3u32);
857        let expected = Uint64::from(33u32);
858        assert_eq!(a * b, expected);
859        assert_eq!(a * &b, expected);
860        assert_eq!(&a * b, expected);
861        assert_eq!(&a * &b, expected);
862    }
863
864    #[test]
865    fn uint64_mul_assign_works() {
866        let mut a = Uint64::from(14u32);
867        a *= Uint64::from(2u32);
868        assert_eq!(a, Uint64::from(28u32));
869
870        // works for refs
871        let mut a = Uint64::from(10u32);
872        let b = Uint64::from(3u32);
873        a *= &b;
874        assert_eq!(a, Uint64::from(30u32));
875    }
876
877    #[test]
878    fn uint64_pow_works() {
879        assert_eq!(Uint64::from(2u32).pow(2), Uint64::from(4u32));
880        assert_eq!(Uint64::from(2u32).pow(10), Uint64::from(1024u32));
881    }
882
883    #[test]
884    #[should_panic]
885    fn uint64_pow_overflow_panics() {
886        _ = Uint64::MAX.pow(2u32);
887    }
888
889    #[test]
890    #[should_panic]
891    fn uint64_math_overflow_panics() {
892        // almost_max is 2^64 - 10
893        let almost_max = Uint64(18446744073709551606);
894        let _ = almost_max + Uint64(12);
895    }
896
897    #[test]
898    fn uint64_multiply_ratio_works() {
899        let base = Uint64(500);
900
901        // factor 1/1
902        assert_eq!(base.multiply_ratio(1u64, 1u64), base);
903        assert_eq!(base.multiply_ratio(3u64, 3u64), base);
904        assert_eq!(base.multiply_ratio(654321u64, 654321u64), base);
905        assert_eq!(base.multiply_ratio(u64::MAX, u64::MAX), base);
906
907        // factor 3/2
908        assert_eq!(base.multiply_ratio(3u64, 2u64), Uint64(750));
909        assert_eq!(base.multiply_ratio(333333u64, 222222u64), Uint64(750));
910
911        // factor 2/3 (integer division always floors the result)
912        assert_eq!(base.multiply_ratio(2u64, 3u64), Uint64(333));
913        assert_eq!(base.multiply_ratio(222222u64, 333333u64), Uint64(333));
914
915        // factor 5/6 (integer division always floors the result)
916        assert_eq!(base.multiply_ratio(5u64, 6u64), Uint64(416));
917        assert_eq!(base.multiply_ratio(100u64, 120u64), Uint64(416));
918    }
919
920    #[test]
921    fn uint64_multiply_ratio_does_not_overflow_when_result_fits() {
922        // Almost max value for Uint64.
923        let base = Uint64(u64::MAX - 9);
924
925        assert_eq!(base.multiply_ratio(2u64, 2u64), base);
926    }
927
928    #[test]
929    #[should_panic]
930    fn uint64_multiply_ratio_panicks_on_overflow() {
931        // Almost max value for Uint64.
932        let base = Uint64(u64::MAX - 9);
933
934        assert_eq!(base.multiply_ratio(2u64, 1u64), base);
935    }
936
937    #[test]
938    #[should_panic(expected = "Denominator must not be zero")]
939    fn uint64_multiply_ratio_panics_for_zero_denominator() {
940        _ = Uint64(500).multiply_ratio(1u64, 0u64);
941    }
942
943    #[test]
944    fn uint64_checked_multiply_ratio_does_not_panic() {
945        assert_eq!(
946            Uint64(500u64).checked_multiply_ratio(1u64, 0u64),
947            Err(CheckedMultiplyRatioError::DivideByZero),
948        );
949        assert_eq!(
950            Uint64(500u64).checked_multiply_ratio(u64::MAX, 1u64),
951            Err(CheckedMultiplyRatioError::Overflow),
952        );
953    }
954
955    #[test]
956    fn uint64_shr_works() {
957        let original = Uint64::new(u64::from_be_bytes([0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8]));
958
959        let shifted = Uint64::new(u64::from_be_bytes([
960            0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8,
961        ]));
962
963        assert_eq!(original >> 2u32, shifted);
964    }
965
966    #[test]
967    #[should_panic]
968    fn uint64_shr_overflow_panics() {
969        let _ = Uint64::from(1u32) >> 64u32;
970    }
971
972    #[test]
973    fn uint64_shl_works() {
974        let original = Uint64::new(u64::from_be_bytes([
975            64u8, 128u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
976        ]));
977
978        let shifted = Uint64::new(u64::from_be_bytes([2u8, 0u8, 4u8, 0u8, 0u8, 0u8, 0u8, 0u8]));
979
980        assert_eq!(original << 2u32, shifted);
981    }
982
983    #[test]
984    #[should_panic]
985    fn uint64_shl_overflow_panics() {
986        let _ = Uint64::from(1u32) << 64u32;
987    }
988
989    #[test]
990    fn sum_works() {
991        let nums = vec![Uint64(17), Uint64(123), Uint64(540), Uint64(82)];
992        let expected = Uint64(762);
993
994        let sum_as_ref: Uint64 = nums.iter().sum();
995        assert_eq!(expected, sum_as_ref);
996
997        let sum_as_owned: Uint64 = nums.into_iter().sum();
998        assert_eq!(expected, sum_as_owned);
999    }
1000
1001    #[test]
1002    fn uint64_methods() {
1003        // checked_*
1004        assert!(matches!(
1005            Uint64::MAX.checked_add(Uint64(1)),
1006            Err(OverflowError { .. })
1007        ));
1008        assert!(matches!(Uint64(1).checked_add(Uint64(1)), Ok(Uint64(2))));
1009        assert!(matches!(
1010            Uint64(0).checked_sub(Uint64(1)),
1011            Err(OverflowError { .. })
1012        ));
1013        assert!(matches!(Uint64(2).checked_sub(Uint64(1)), Ok(Uint64(1))));
1014        assert!(matches!(
1015            Uint64::MAX.checked_mul(Uint64(2)),
1016            Err(OverflowError { .. })
1017        ));
1018        assert!(matches!(Uint64(2).checked_mul(Uint64(2)), Ok(Uint64(4))));
1019        assert!(matches!(
1020            Uint64::MAX.checked_pow(2u32),
1021            Err(OverflowError { .. })
1022        ));
1023        assert!(matches!(Uint64(2).checked_pow(3), Ok(Uint64(8))));
1024        assert!(matches!(
1025            Uint64::MAX.checked_div(Uint64(0)),
1026            Err(DivideByZeroError { .. })
1027        ));
1028        assert!(matches!(Uint64(6).checked_div(Uint64(2)), Ok(Uint64(3))));
1029        assert!(matches!(
1030            Uint64::MAX.checked_div_euclid(Uint64(0)),
1031            Err(DivideByZeroError { .. })
1032        ));
1033        assert!(matches!(
1034            Uint64(6).checked_div_euclid(Uint64(2)),
1035            Ok(Uint64(3)),
1036        ));
1037        assert!(matches!(
1038            Uint64::MAX.checked_rem(Uint64(0)),
1039            Err(DivideByZeroError { .. })
1040        ));
1041        assert!(matches!(Uint64(7).checked_rem(Uint64(2)), Ok(Uint64(1))));
1042
1043        // saturating_*
1044        assert_eq!(Uint64::MAX.saturating_add(Uint64(1)), Uint64::MAX);
1045        assert_eq!(Uint64(0).saturating_sub(Uint64(1)), Uint64(0));
1046        assert_eq!(Uint64::MAX.saturating_mul(Uint64(2)), Uint64::MAX);
1047        assert_eq!(Uint64::MAX.saturating_pow(2), Uint64::MAX);
1048    }
1049
1050    #[test]
1051    fn uint64_wrapping_methods() {
1052        // wrapping_add
1053        assert_eq!(Uint64(2).wrapping_add(Uint64(2)), Uint64(4)); // non-wrapping
1054        assert_eq!(Uint64::MAX.wrapping_add(Uint64(1)), Uint64(0)); // wrapping
1055
1056        // wrapping_sub
1057        assert_eq!(Uint64(7).wrapping_sub(Uint64(5)), Uint64(2)); // non-wrapping
1058        assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64::MAX); // wrapping
1059
1060        // wrapping_mul
1061        assert_eq!(Uint64(3).wrapping_mul(Uint64(2)), Uint64(6)); // non-wrapping
1062        assert_eq!(
1063            Uint64::MAX.wrapping_mul(Uint64(2)),
1064            Uint64::MAX - Uint64::one()
1065        ); // wrapping
1066
1067        // wrapping_pow
1068        assert_eq!(Uint64(2).wrapping_pow(3), Uint64(8)); // non-wrapping
1069        assert_eq!(Uint64::MAX.wrapping_pow(2), Uint64(1)); // wrapping
1070    }
1071
1072    #[test]
1073    #[allow(clippy::op_ref)]
1074    fn uint64_implements_rem() {
1075        let a = Uint64::new(10);
1076        assert_eq!(a % Uint64::new(10), Uint64::zero());
1077        assert_eq!(a % Uint64::new(2), Uint64::zero());
1078        assert_eq!(a % Uint64::new(1), Uint64::zero());
1079        assert_eq!(a % Uint64::new(3), Uint64::new(1));
1080        assert_eq!(a % Uint64::new(4), Uint64::new(2));
1081
1082        // works for refs
1083        let a = Uint64::new(10);
1084        let b = Uint64::new(3);
1085        let expected = Uint64::new(1);
1086        assert_eq!(a % b, expected);
1087        assert_eq!(a % &b, expected);
1088        assert_eq!(&a % b, expected);
1089        assert_eq!(&a % &b, expected);
1090    }
1091
1092    #[test]
1093    #[should_panic(expected = "divisor of zero")]
1094    fn uint64_rem_panics_for_zero() {
1095        let _ = Uint64::new(10) % Uint64::zero();
1096    }
1097
1098    #[test]
1099    #[allow(clippy::op_ref)]
1100    fn uint64_rem_works() {
1101        assert_eq!(
1102            Uint64::from(12u32) % Uint64::from(10u32),
1103            Uint64::from(2u32)
1104        );
1105        assert_eq!(Uint64::from(50u32) % Uint64::from(5u32), Uint64::zero());
1106
1107        // works for refs
1108        let a = Uint64::from(42u32);
1109        let b = Uint64::from(5u32);
1110        let expected = Uint64::from(2u32);
1111        assert_eq!(a % b, expected);
1112        assert_eq!(a % &b, expected);
1113        assert_eq!(&a % b, expected);
1114        assert_eq!(&a % &b, expected);
1115    }
1116
1117    #[test]
1118    fn uint64_rem_assign_works() {
1119        let mut a = Uint64::from(30u32);
1120        a %= Uint64::from(4u32);
1121        assert_eq!(a, Uint64::from(2u32));
1122
1123        // works for refs
1124        let mut a = Uint64::from(25u32);
1125        let b = Uint64::from(6u32);
1126        a %= &b;
1127        assert_eq!(a, Uint64::from(1u32));
1128    }
1129
1130    #[test]
1131    fn uint64_strict_add_works() {
1132        let a = Uint64::new(5);
1133        let b = Uint64::new(3);
1134        assert_eq!(a.strict_add(b), Uint64::new(8));
1135        assert_eq!(b.strict_add(a), Uint64::new(8));
1136    }
1137
1138    #[test]
1139    #[should_panic(expected = "attempt to add with overflow")]
1140    fn uint64_strict_add_panics_on_overflow() {
1141        let a = Uint64::MAX;
1142        let b = Uint64::ONE;
1143        let _ = a.strict_add(b);
1144    }
1145
1146    #[test]
1147    fn uint64_strict_sub_works() {
1148        let a = Uint64::new(5);
1149        let b = Uint64::new(3);
1150        assert_eq!(a.strict_sub(b), Uint64::new(2));
1151    }
1152
1153    #[test]
1154    #[should_panic(expected = "attempt to subtract with overflow")]
1155    fn uint64_strict_sub_panics_on_overflow() {
1156        let a = Uint64::ZERO;
1157        let b = Uint64::ONE;
1158        let _ = a.strict_sub(b);
1159    }
1160
1161    #[test]
1162    fn uint64_abs_diff_works() {
1163        let a = Uint64::from(42u32);
1164        let b = Uint64::from(5u32);
1165        let expected = Uint64::from(37u32);
1166        assert_eq!(a.abs_diff(b), expected);
1167        assert_eq!(b.abs_diff(a), expected);
1168    }
1169
1170    #[test]
1171    fn uint64_partial_eq() {
1172        let test_cases = [(1, 1, true), (42, 42, true), (42, 24, false), (0, 0, true)]
1173            .into_iter()
1174            .map(|(lhs, rhs, expected)| (Uint64::new(lhs), Uint64::new(rhs), expected));
1175
1176        #[allow(clippy::op_ref)]
1177        for (lhs, rhs, expected) in test_cases {
1178            assert_eq!(lhs == rhs, expected);
1179            assert_eq!(&lhs == rhs, expected);
1180            assert_eq!(lhs == &rhs, expected);
1181            assert_eq!(&lhs == &rhs, expected);
1182        }
1183    }
1184
1185    #[test]
1186    fn mul_floor_works_with_zero() {
1187        let fraction = (0u32, 21u32);
1188        let res = Uint64::new(123456).mul_floor(fraction);
1189        assert_eq!(Uint64::zero(), res)
1190    }
1191
1192    #[test]
1193    fn mul_floor_does_nothing_with_one() {
1194        let fraction = (Uint64::one(), Uint64::one());
1195        let res = Uint64::new(123456).mul_floor(fraction);
1196        assert_eq!(Uint64::new(123456), res)
1197    }
1198
1199    #[test]
1200    fn mul_floor_rounds_down_with_normal_case() {
1201        let fraction = (8u64, 21u64);
1202        let res = Uint64::new(123456).mul_floor(fraction); // 47030.8571
1203        assert_eq!(Uint64::new(47030), res)
1204    }
1205
1206    #[test]
1207    fn mul_floor_does_not_round_on_even_divide() {
1208        let fraction = (2u64, 5u64);
1209        let res = Uint64::new(25).mul_floor(fraction);
1210        assert_eq!(Uint64::new(10), res)
1211    }
1212
1213    #[test]
1214    fn mul_floor_works_when_operation_temporarily_takes_above_max() {
1215        let fraction = (8u64, 21u64);
1216        let res = Uint64::MAX.mul_floor(fraction); // 7_027_331_075_698_876_805.71428571
1217        assert_eq!(Uint64::new(7_027_331_075_698_876_805), res)
1218    }
1219
1220    #[test]
1221    #[should_panic(expected = "ConversionOverflowError")]
1222    fn mul_floor_panics_on_overflow() {
1223        let fraction = (21u64, 8u64);
1224        _ = Uint64::MAX.mul_floor(fraction);
1225    }
1226
1227    #[test]
1228    fn checked_mul_floor_does_not_panic_on_overflow() {
1229        let fraction = (21u64, 8u64);
1230        assert_eq!(
1231            Uint64::MAX.checked_mul_floor(fraction),
1232            Err(ConversionOverflow(ConversionOverflowError {
1233                source_type: "Uint128",
1234                target_type: "Uint64",
1235            })),
1236        );
1237    }
1238
1239    #[test]
1240    #[should_panic(expected = "DivideByZeroError")]
1241    fn mul_floor_panics_on_zero_div() {
1242        let fraction = (21u64, 0u64);
1243        _ = Uint64::new(123456).mul_floor(fraction);
1244    }
1245
1246    #[test]
1247    fn checked_mul_floor_does_not_panic_on_zero_div() {
1248        let fraction = (21u64, 0u64);
1249        assert_eq!(
1250            Uint64::new(123456).checked_mul_floor(fraction),
1251            Err(DivideByZero(DivideByZeroError)),
1252        );
1253    }
1254
1255    #[test]
1256    fn mul_ceil_works_with_zero() {
1257        let fraction = (Uint64::zero(), Uint64::new(21));
1258        let res = Uint64::new(123456).mul_ceil(fraction);
1259        assert_eq!(Uint64::zero(), res)
1260    }
1261
1262    #[test]
1263    fn mul_ceil_does_nothing_with_one() {
1264        let fraction = (Uint64::one(), Uint64::one());
1265        let res = Uint64::new(123456).mul_ceil(fraction);
1266        assert_eq!(Uint64::new(123456), res)
1267    }
1268
1269    #[test]
1270    fn mul_ceil_rounds_up_with_normal_case() {
1271        let fraction = (8u64, 21u64);
1272        let res = Uint64::new(123456).mul_ceil(fraction); // 47030.8571
1273        assert_eq!(Uint64::new(47031), res)
1274    }
1275
1276    #[test]
1277    fn mul_ceil_does_not_round_on_even_divide() {
1278        let fraction = (2u64, 5u64);
1279        let res = Uint64::new(25).mul_ceil(fraction);
1280        assert_eq!(Uint64::new(10), res)
1281    }
1282
1283    #[test]
1284    fn mul_ceil_works_when_operation_temporarily_takes_above_max() {
1285        let fraction = (8u64, 21u64);
1286        let res = Uint64::MAX.mul_ceil(fraction); // 7_027_331_075_698_876_805.71428571
1287        assert_eq!(Uint64::new(7_027_331_075_698_876_806), res)
1288    }
1289
1290    #[test]
1291    #[should_panic(expected = "ConversionOverflowError")]
1292    fn mul_ceil_panics_on_overflow() {
1293        let fraction = (21u64, 8u64);
1294        _ = Uint64::MAX.mul_ceil(fraction);
1295    }
1296
1297    #[test]
1298    fn checked_mul_ceil_does_not_panic_on_overflow() {
1299        let fraction = (21u64, 8u64);
1300        assert_eq!(
1301            Uint64::MAX.checked_mul_ceil(fraction),
1302            Err(ConversionOverflow(ConversionOverflowError {
1303                source_type: "Uint128",
1304                target_type: "Uint64",
1305            })),
1306        );
1307    }
1308
1309    #[test]
1310    #[should_panic(expected = "DivideByZeroError")]
1311    fn mul_ceil_panics_on_zero_div() {
1312        let fraction = (21u64, 0u64);
1313        _ = Uint64::new(123456).mul_ceil(fraction);
1314    }
1315
1316    #[test]
1317    fn checked_mul_ceil_does_not_panic_on_zero_div() {
1318        let fraction = (21u64, 0u64);
1319        assert_eq!(
1320            Uint64::new(123456).checked_mul_ceil(fraction),
1321            Err(DivideByZero(DivideByZeroError)),
1322        );
1323    }
1324
1325    #[test]
1326    #[should_panic(expected = "DivideByZeroError")]
1327    fn div_floor_raises_with_zero() {
1328        let fraction = (Uint64::zero(), Uint64::new(21));
1329        _ = Uint64::new(123456).div_floor(fraction);
1330    }
1331
1332    #[test]
1333    fn div_floor_does_nothing_with_one() {
1334        let fraction = (Uint64::one(), Uint64::one());
1335        let res = Uint64::new(123456).div_floor(fraction);
1336        assert_eq!(Uint64::new(123456), res)
1337    }
1338
1339    #[test]
1340    fn div_floor_rounds_down_with_normal_case() {
1341        let fraction = (5u64, 21u64);
1342        let res = Uint64::new(123456).div_floor(fraction); // 518515.2
1343        assert_eq!(Uint64::new(518515), res)
1344    }
1345
1346    #[test]
1347    fn div_floor_does_not_round_on_even_divide() {
1348        let fraction = (5u64, 2u64);
1349        let res = Uint64::new(25).div_floor(fraction);
1350        assert_eq!(Uint64::new(10), res)
1351    }
1352
1353    #[test]
1354    fn div_floor_works_when_operation_temporarily_takes_above_max() {
1355        let fraction = (21u64, 8u64);
1356        let res = Uint64::MAX.div_floor(fraction); // 7_027_331_075_698_876_805.71428
1357        assert_eq!(Uint64::new(7_027_331_075_698_876_805), res)
1358    }
1359
1360    #[test]
1361    #[should_panic(expected = "ConversionOverflowError")]
1362    fn div_floor_panics_on_overflow() {
1363        let fraction = (8u64, 21u64);
1364        _ = Uint64::MAX.div_floor(fraction);
1365    }
1366
1367    #[test]
1368    fn div_floor_does_not_panic_on_overflow() {
1369        let fraction = (8u64, 21u64);
1370        assert_eq!(
1371            Uint64::MAX.checked_div_floor(fraction),
1372            Err(ConversionOverflow(ConversionOverflowError {
1373                source_type: "Uint128",
1374                target_type: "Uint64",
1375            })),
1376        );
1377    }
1378
1379    #[test]
1380    #[should_panic(expected = "DivideByZeroError")]
1381    fn div_ceil_raises_with_zero() {
1382        let fraction = (Uint64::zero(), Uint64::new(21));
1383        _ = Uint64::new(123456).div_ceil(fraction);
1384    }
1385
1386    #[test]
1387    fn div_ceil_does_nothing_with_one() {
1388        let fraction = (Uint64::one(), Uint64::one());
1389        let res = Uint64::new(123456).div_ceil(fraction);
1390        assert_eq!(Uint64::new(123456), res)
1391    }
1392
1393    #[test]
1394    fn div_ceil_rounds_up_with_normal_case() {
1395        let fraction = (5u64, 21u64);
1396        let res = Uint64::new(123456).div_ceil(fraction); // 518515.2
1397        assert_eq!(Uint64::new(518516), res)
1398    }
1399
1400    #[test]
1401    fn div_ceil_does_not_round_on_even_divide() {
1402        let fraction = (5u64, 2u64);
1403        let res = Uint64::new(25).div_ceil(fraction);
1404        assert_eq!(Uint64::new(10), res)
1405    }
1406
1407    #[test]
1408    fn div_ceil_works_when_operation_temporarily_takes_above_max() {
1409        let fraction = (21u64, 8u64);
1410        let res = Uint64::MAX.div_ceil(fraction); // 7_027_331_075_698_876_805.71428
1411        assert_eq!(Uint64::new(7_027_331_075_698_876_806), res)
1412    }
1413
1414    #[test]
1415    #[should_panic(expected = "ConversionOverflowError")]
1416    fn div_ceil_panics_on_overflow() {
1417        let fraction = (8u64, 21u64);
1418        _ = Uint64::MAX.div_ceil(fraction);
1419    }
1420
1421    #[test]
1422    fn div_ceil_does_not_panic_on_overflow() {
1423        let fraction = (8u64, 21u64);
1424        assert_eq!(
1425            Uint64::MAX.checked_div_ceil(fraction),
1426            Err(ConversionOverflow(ConversionOverflowError {
1427                source_type: "Uint128",
1428                target_type: "Uint64",
1429            })),
1430        );
1431    }
1432}