Skip to main content

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