secret_cosmwasm_std/math/
uint64.rs

1use forward_ref::{forward_ref_binop, forward_ref_op_assign};
2use schemars::JsonSchema;
3use serde::{de, ser, Deserialize, Deserializer, Serialize};
4use std::fmt::{self};
5use std::ops::{
6    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shr, ShrAssign, Sub, SubAssign,
7};
8
9use crate::errors::{
10    CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError,
11};
12use crate::Uint128;
13
14/// A thin wrapper around u64 that is using strings for JSON encoding/decoding,
15/// such that the full u64 range can be used for clients that convert JSON numbers to floats,
16/// like JavaScript and jq.
17///
18/// # Examples
19///
20/// Use `from` to create instances of this and `u64` to get the value out:
21///
22/// ```
23/// # use secret_cosmwasm_std::Uint64;
24/// let a = Uint64::from(42u64);
25/// assert_eq!(a.u64(), 42);
26///
27/// let b = Uint64::from(70u32);
28/// assert_eq!(b.u64(), 70);
29/// ```
30#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
31pub struct Uint64(#[schemars(with = "String")] u64);
32
33impl Uint64 {
34    pub const MAX: Self = Self(u64::MAX);
35    pub const MIN: Self = Self(u64::MIN);
36
37    /// Creates a Uint64(value).
38    ///
39    /// This method is less flexible than `from` but can be called in a const context.
40    pub const fn new(value: u64) -> Self {
41        Uint64(value)
42    }
43
44    /// Creates a Uint64(0)
45    #[inline]
46    pub const fn zero() -> Self {
47        Uint64(0)
48    }
49
50    /// Creates a Uint64(1)
51    #[inline]
52    pub const fn one() -> Self {
53        Self(1)
54    }
55
56    /// Returns a copy of the internal data
57    pub const fn u64(&self) -> u64 {
58        self.0
59    }
60
61    /// Returns a copy of the number as big endian bytes.
62    pub const fn to_be_bytes(self) -> [u8; 8] {
63        self.0.to_be_bytes()
64    }
65
66    /// Returns a copy of the number as little endian bytes.
67    pub const fn to_le_bytes(self) -> [u8; 8] {
68        self.0.to_le_bytes()
69    }
70
71    pub const fn is_zero(&self) -> bool {
72        self.0 == 0
73    }
74
75    pub fn pow(self, exp: u32) -> Self {
76        self.0.pow(exp).into()
77    }
78
79    /// Returns `self * numerator / denominator`.
80    ///
81    /// Due to the nature of the integer division involved, the result is always floored.
82    /// E.g. 5 * 99/100 = 4.
83    pub fn multiply_ratio<A: Into<u64>, B: Into<u64>>(
84        &self,
85        numerator: A,
86        denominator: B,
87    ) -> Uint64 {
88        match self.checked_multiply_ratio(numerator, denominator) {
89            Ok(value) => value,
90            Err(CheckedMultiplyRatioError::DivideByZero) => {
91                panic!("Denominator must not be zero")
92            }
93            Err(CheckedMultiplyRatioError::Overflow) => panic!("Multiplication overflow"),
94        }
95    }
96
97    /// Returns `self * numerator / denominator`.
98    ///
99    /// Due to the nature of the integer division involved, the result is always floored.
100    /// E.g. 5 * 99/100 = 4.
101    pub fn checked_multiply_ratio<A: Into<u64>, B: Into<u64>>(
102        &self,
103        numerator: A,
104        denominator: B,
105    ) -> Result<Uint64, CheckedMultiplyRatioError> {
106        let numerator = numerator.into();
107        let denominator = denominator.into();
108        if denominator == 0 {
109            return Err(CheckedMultiplyRatioError::DivideByZero);
110        }
111        match (self.full_mul(numerator) / Uint128::from(denominator)).try_into() {
112            Ok(ratio) => Ok(ratio),
113            Err(_) => Err(CheckedMultiplyRatioError::Overflow),
114        }
115    }
116
117    /// Multiplies two `Uint64`/`u64` values without overflow, producing an
118    /// [`Uint128`].
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use secret_cosmwasm_std::Uint64;
124    ///
125    /// let a = Uint64::MAX;
126    /// let result = a.full_mul(2u32);
127    /// assert_eq!(result.to_string(), "36893488147419103230");
128    /// ```
129    pub fn full_mul(self, rhs: impl Into<u64>) -> Uint128 {
130        Uint128::from(self.u64())
131            .checked_mul(Uint128::from(rhs.into()))
132            .unwrap()
133    }
134
135    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
136        self.0
137            .checked_add(other.0)
138            .map(Self)
139            .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other))
140    }
141
142    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
143        self.0
144            .checked_sub(other.0)
145            .map(Self)
146            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other))
147    }
148
149    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
150        self.0
151            .checked_mul(other.0)
152            .map(Self)
153            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other))
154    }
155
156    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
157        self.0
158            .checked_pow(exp)
159            .map(Self)
160            .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp))
161    }
162
163    pub fn checked_div(self, other: Self) -> Result<Self, DivideByZeroError> {
164        self.0
165            .checked_div(other.0)
166            .map(Self)
167            .ok_or_else(|| DivideByZeroError::new(self))
168    }
169
170    pub fn checked_div_euclid(self, other: Self) -> Result<Self, DivideByZeroError> {
171        self.0
172            .checked_div_euclid(other.0)
173            .map(Self)
174            .ok_or_else(|| DivideByZeroError::new(self))
175    }
176
177    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
178        self.0
179            .checked_rem(other.0)
180            .map(Self)
181            .ok_or_else(|| DivideByZeroError::new(self))
182    }
183
184    #[inline]
185    pub fn wrapping_add(self, other: Self) -> Self {
186        Self(self.0.wrapping_add(other.0))
187    }
188
189    #[inline]
190    pub fn wrapping_sub(self, other: Self) -> Self {
191        Self(self.0.wrapping_sub(other.0))
192    }
193
194    #[inline]
195    pub fn wrapping_mul(self, other: Self) -> Self {
196        Self(self.0.wrapping_mul(other.0))
197    }
198
199    #[inline]
200    pub fn wrapping_pow(self, other: u32) -> Self {
201        Self(self.0.wrapping_pow(other))
202    }
203
204    pub fn saturating_add(self, other: Self) -> Self {
205        Self(self.0.saturating_add(other.0))
206    }
207
208    pub fn saturating_sub(self, other: Self) -> Self {
209        Self(self.0.saturating_sub(other.0))
210    }
211
212    pub fn saturating_mul(self, other: Self) -> Self {
213        Self(self.0.saturating_mul(other.0))
214    }
215
216    pub fn saturating_pow(self, exp: u32) -> Self {
217        Self(self.0.saturating_pow(exp))
218    }
219
220    pub const fn abs_diff(self, other: Self) -> Self {
221        Self(if self.0 < other.0 {
222            other.0 - self.0
223        } else {
224            self.0 - other.0
225        })
226    }
227}
228
229// `From<u{128,64,32,16,8}>` is implemented manually instead of
230// using `impl<T: Into<u64>> From<T> for Uint64` because
231// of the conflict with `TryFrom<&str>` as described here
232// https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error
233
234impl From<u64> for Uint64 {
235    fn from(val: u64) -> Self {
236        Uint64(val)
237    }
238}
239
240impl From<u32> for Uint64 {
241    fn from(val: u32) -> Self {
242        Uint64(val.into())
243    }
244}
245
246impl From<u16> for Uint64 {
247    fn from(val: u16) -> Self {
248        Uint64(val.into())
249    }
250}
251
252impl From<u8> for Uint64 {
253    fn from(val: u8) -> Self {
254        Uint64(val.into())
255    }
256}
257
258impl TryFrom<&str> for Uint64 {
259    type Error = StdError;
260
261    fn try_from(val: &str) -> Result<Self, Self::Error> {
262        match val.parse::<u64>() {
263            Ok(u) => Ok(Uint64(u)),
264            Err(e) => Err(StdError::generic_err(format!("Parsing u64: {}", e))),
265        }
266    }
267}
268
269impl From<Uint64> for String {
270    fn from(original: Uint64) -> Self {
271        original.to_string()
272    }
273}
274
275impl From<Uint64> for u64 {
276    fn from(original: Uint64) -> Self {
277        original.0
278    }
279}
280
281impl fmt::Display for Uint64 {
282    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
283        self.0.fmt(f)
284    }
285}
286
287impl Add<Uint64> for Uint64 {
288    type Output = Self;
289
290    fn add(self, rhs: Self) -> Self {
291        Uint64(self.u64().checked_add(rhs.u64()).unwrap())
292    }
293}
294
295impl<'a> Add<&'a Uint64> for Uint64 {
296    type Output = Self;
297
298    fn add(self, rhs: &'a Uint64) -> Self {
299        Uint64(self.u64().checked_add(rhs.u64()).unwrap())
300    }
301}
302
303impl Sub<Uint64> for Uint64 {
304    type Output = Self;
305
306    fn sub(self, rhs: Self) -> Self {
307        Uint64(
308            self.u64()
309                .checked_sub(rhs.u64())
310                .expect("attempt to subtract with overflow"),
311        )
312    }
313}
314forward_ref_binop!(impl Sub, sub for Uint64, Uint64);
315
316impl SubAssign<Uint64> for Uint64 {
317    fn sub_assign(&mut self, rhs: Uint64) {
318        *self = *self - rhs;
319    }
320}
321forward_ref_op_assign!(impl SubAssign, sub_assign for Uint64, Uint64);
322
323impl Mul<Uint64> for Uint64 {
324    type Output = Self;
325
326    fn mul(self, rhs: Self) -> Self::Output {
327        Self(
328            self.u64()
329                .checked_mul(rhs.u64())
330                .expect("attempt to multiply with overflow"),
331        )
332    }
333}
334forward_ref_binop!(impl Mul, mul for Uint64, Uint64);
335
336impl MulAssign<Uint64> for Uint64 {
337    fn mul_assign(&mut self, rhs: Self) {
338        *self = *self * rhs;
339    }
340}
341forward_ref_op_assign!(impl MulAssign, mul_assign for Uint64, Uint64);
342
343impl Div<Uint64> for Uint64 {
344    type Output = Self;
345
346    fn div(self, rhs: Self) -> Self::Output {
347        Self(self.u64().checked_div(rhs.u64()).unwrap())
348    }
349}
350
351impl<'a> Div<&'a Uint64> for Uint64 {
352    type Output = Self;
353
354    fn div(self, rhs: &'a Uint64) -> Self::Output {
355        Self(self.u64().checked_div(rhs.u64()).unwrap())
356    }
357}
358
359impl Rem for Uint64 {
360    type Output = Self;
361
362    /// # Panics
363    ///
364    /// This operation will panic if `rhs` is zero.
365    #[inline]
366    fn rem(self, rhs: Self) -> Self {
367        Self(self.0.rem(rhs.0))
368    }
369}
370forward_ref_binop!(impl Rem, rem for Uint64, Uint64);
371
372impl RemAssign<Uint64> for Uint64 {
373    fn rem_assign(&mut self, rhs: Uint64) {
374        *self = *self % rhs;
375    }
376}
377forward_ref_op_assign!(impl RemAssign, rem_assign for Uint64, Uint64);
378
379impl Shr<u32> for Uint64 {
380    type Output = Self;
381
382    fn shr(self, rhs: u32) -> Self::Output {
383        Self(self.u64().checked_shr(rhs).unwrap())
384    }
385}
386
387impl<'a> Shr<&'a u32> for Uint64 {
388    type Output = Self;
389
390    fn shr(self, rhs: &'a u32) -> Self::Output {
391        Self(self.u64().checked_shr(*rhs).unwrap())
392    }
393}
394
395impl AddAssign<Uint64> for Uint64 {
396    fn add_assign(&mut self, rhs: Uint64) {
397        self.0 = self.0.checked_add(rhs.u64()).unwrap();
398    }
399}
400
401impl<'a> AddAssign<&'a Uint64> for Uint64 {
402    fn add_assign(&mut self, rhs: &'a Uint64) {
403        self.0 = self.0.checked_add(rhs.u64()).unwrap();
404    }
405}
406
407impl DivAssign<Uint64> for Uint64 {
408    fn div_assign(&mut self, rhs: Self) {
409        self.0 = self.0.checked_div(rhs.u64()).unwrap();
410    }
411}
412
413impl<'a> DivAssign<&'a Uint64> for Uint64 {
414    fn div_assign(&mut self, rhs: &'a Uint64) {
415        self.0 = self.0.checked_div(rhs.u64()).unwrap();
416    }
417}
418
419impl ShrAssign<u32> for Uint64 {
420    fn shr_assign(&mut self, rhs: u32) {
421        self.0 = self.0.checked_shr(rhs).unwrap();
422    }
423}
424
425impl<'a> ShrAssign<&'a u32> for Uint64 {
426    fn shr_assign(&mut self, rhs: &'a u32) {
427        self.0 = self.0.checked_shr(*rhs).unwrap();
428    }
429}
430
431impl Serialize for Uint64 {
432    /// Serializes as an integer string using base 10
433    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
434    where
435        S: ser::Serializer,
436    {
437        serializer.serialize_str(&self.to_string())
438    }
439}
440
441impl<'de> Deserialize<'de> for Uint64 {
442    /// Deserialized from an integer string using base 10
443    fn deserialize<D>(deserializer: D) -> Result<Uint64, D::Error>
444    where
445        D: Deserializer<'de>,
446    {
447        deserializer.deserialize_str(Uint64Visitor)
448    }
449}
450
451struct Uint64Visitor;
452
453impl<'de> de::Visitor<'de> for Uint64Visitor {
454    type Value = Uint64;
455
456    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
457        formatter.write_str("string-encoded integer")
458    }
459
460    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
461    where
462        E: de::Error,
463    {
464        match v.parse::<u64>() {
465            Ok(u) => Ok(Uint64(u)),
466            Err(e) => Err(E::custom(format!("invalid Uint64 '{}' - {}", v, e))),
467        }
468    }
469}
470
471impl<A> std::iter::Sum<A> for Uint64
472where
473    Self: Add<A, Output = Self>,
474{
475    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
476        iter.fold(Self::zero(), Add::add)
477    }
478}
479
480impl PartialEq<&Uint64> for Uint64 {
481    fn eq(&self, rhs: &&Uint64) -> bool {
482        self == *rhs
483    }
484}
485
486impl PartialEq<Uint64> for &Uint64 {
487    fn eq(&self, rhs: &Uint64) -> bool {
488        *self == rhs
489    }
490}
491
492#[cfg(test)]
493mod tests {
494    use super::*;
495    use crate::{from_slice, to_vec};
496
497    #[test]
498    fn uint64_zero_works() {
499        let zero = Uint64::zero();
500        assert_eq!(zero.to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
501    }
502
503    #[test]
504    fn uint64_one_works() {
505        let one = Uint64::one();
506        assert_eq!(one.to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 1]);
507    }
508
509    #[test]
510    fn uint64_convert_into() {
511        let original = Uint64(12345);
512        let a = u64::from(original);
513        assert_eq!(a, 12345);
514
515        let original = Uint64(12345);
516        let a = String::from(original);
517        assert_eq!(a, "12345");
518    }
519
520    #[test]
521    fn uint64_convert_from() {
522        let a = Uint64::from(5u64);
523        assert_eq!(a.0, 5);
524
525        let a = Uint64::from(5u32);
526        assert_eq!(a.0, 5);
527
528        let a = Uint64::from(5u16);
529        assert_eq!(a.0, 5);
530
531        let a = Uint64::from(5u8);
532        assert_eq!(a.0, 5);
533
534        let result = Uint64::try_from("34567");
535        assert_eq!(result.unwrap().0, 34567);
536
537        let result = Uint64::try_from("1.23");
538        assert!(result.is_err());
539    }
540
541    #[test]
542    fn uint64_implements_display() {
543        let a = Uint64(12345);
544        assert_eq!(format!("Embedded: {}", a), "Embedded: 12345");
545        assert_eq!(a.to_string(), "12345");
546
547        let a = Uint64(0);
548        assert_eq!(format!("Embedded: {}", a), "Embedded: 0");
549        assert_eq!(a.to_string(), "0");
550    }
551
552    #[test]
553    fn uint64_display_padding_works() {
554        let a = Uint64::from(123u64);
555        assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123");
556    }
557
558    #[test]
559    fn uint64_to_be_bytes_works() {
560        assert_eq!(Uint64::zero().to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
561        assert_eq!(
562            Uint64::MAX.to_be_bytes(),
563            [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
564        );
565        assert_eq!(Uint64::new(1).to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 1]);
566        // Python: `[b for b in (63374607431768124608).to_bytes(8, "big")]`
567        assert_eq!(
568            Uint64::new(874607431768124608).to_be_bytes(),
569            [12, 35, 58, 211, 72, 116, 172, 192]
570        );
571    }
572
573    #[test]
574    fn uint64_to_le_bytes_works() {
575        assert_eq!(Uint64::zero().to_le_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]);
576        assert_eq!(
577            Uint64::MAX.to_le_bytes(),
578            [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
579        );
580        assert_eq!(Uint64::new(1).to_le_bytes(), [1, 0, 0, 0, 0, 0, 0, 0]);
581        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(16, "little")]`
582        assert_eq!(
583            Uint64::new(874607431768124608).to_le_bytes(),
584            [192, 172, 116, 72, 211, 58, 35, 12]
585        );
586    }
587
588    #[test]
589    fn uint64_is_zero_works() {
590        assert!(Uint64::zero().is_zero());
591        assert!(Uint64(0).is_zero());
592
593        assert!(!Uint64(1).is_zero());
594        assert!(!Uint64(123).is_zero());
595    }
596
597    #[test]
598    fn uint64_json() {
599        let orig = Uint64(1234567890987654321);
600        let serialized = to_vec(&orig).unwrap();
601        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
602        let parsed: Uint64 = from_slice(&serialized).unwrap();
603        assert_eq!(parsed, orig);
604    }
605
606    #[test]
607    fn uint64_compare() {
608        let a = Uint64(12345);
609        let b = Uint64(23456);
610
611        assert!(a < b);
612        assert!(b > a);
613        assert_eq!(a, Uint64(12345));
614    }
615
616    #[test]
617    #[allow(clippy::op_ref)]
618    fn uint64_math() {
619        let a = Uint64(12345);
620        let b = Uint64(23456);
621
622        // test + with owned and reference right hand side
623        assert_eq!(a + b, Uint64(35801));
624        assert_eq!(a + &b, Uint64(35801));
625
626        // test - with owned and reference right hand side
627        assert_eq!((b.checked_sub(a)).unwrap(), Uint64(11111));
628
629        // test += with owned and reference right hand side
630        let mut c = Uint64(300000);
631        c += b;
632        assert_eq!(c, Uint64(323456));
633        let mut d = Uint64(300000);
634        d += &b;
635        assert_eq!(d, Uint64(323456));
636
637        // error result on underflow (- would produce negative result)
638        let underflow_result = a.checked_sub(b);
639        let OverflowError {
640            operand1, operand2, ..
641        } = underflow_result.unwrap_err();
642        assert_eq!((operand1, operand2), (a.to_string(), b.to_string()));
643    }
644
645    #[test]
646    #[allow(clippy::op_ref)]
647    fn uint64_sub_works() {
648        assert_eq!(Uint64(2) - Uint64(1), Uint64(1));
649        assert_eq!(Uint64(2) - Uint64(0), Uint64(2));
650        assert_eq!(Uint64(2) - Uint64(2), Uint64(0));
651
652        // works for refs
653        let a = Uint64::new(10);
654        let b = Uint64::new(3);
655        let expected = Uint64::new(7);
656        assert_eq!(a - b, expected);
657        assert_eq!(a - &b, expected);
658        assert_eq!(&a - b, expected);
659        assert_eq!(&a - &b, expected);
660    }
661
662    #[test]
663    #[should_panic]
664    fn uint64_sub_overflow_panics() {
665        let _ = Uint64(1) - Uint64(2);
666    }
667
668    #[test]
669    fn uint64_sub_assign_works() {
670        let mut a = Uint64(14);
671        a -= Uint64(2);
672        assert_eq!(a, Uint64(12));
673
674        // works for refs
675        let mut a = Uint64::new(10);
676        let b = Uint64::new(3);
677        let expected = Uint64::new(7);
678        a -= &b;
679        assert_eq!(a, expected);
680    }
681
682    #[test]
683    #[allow(clippy::op_ref)]
684    fn uint64_mul_works() {
685        assert_eq!(Uint64::from(2u32) * Uint64::from(3u32), Uint64::from(6u32));
686        assert_eq!(Uint64::from(2u32) * Uint64::zero(), Uint64::zero());
687
688        // works for refs
689        let a = Uint64::from(11u32);
690        let b = Uint64::from(3u32);
691        let expected = Uint64::from(33u32);
692        assert_eq!(a * b, expected);
693        assert_eq!(a * &b, expected);
694        assert_eq!(&a * b, expected);
695        assert_eq!(&a * &b, expected);
696    }
697
698    #[test]
699    fn uint64_mul_assign_works() {
700        let mut a = Uint64::from(14u32);
701        a *= Uint64::from(2u32);
702        assert_eq!(a, Uint64::from(28u32));
703
704        // works for refs
705        let mut a = Uint64::from(10u32);
706        let b = Uint64::from(3u32);
707        a *= &b;
708        assert_eq!(a, Uint64::from(30u32));
709    }
710
711    #[test]
712    fn uint64_pow_works() {
713        assert_eq!(Uint64::from(2u32).pow(2), Uint64::from(4u32));
714        assert_eq!(Uint64::from(2u32).pow(10), Uint64::from(1024u32));
715    }
716
717    #[test]
718    #[should_panic]
719    fn uint64_pow_overflow_panics() {
720        Uint64::MAX.pow(2u32);
721    }
722
723    #[test]
724    #[should_panic]
725    fn uint64_math_overflow_panics() {
726        // almost_max is 2^64 - 10
727        let almost_max = Uint64(18446744073709551606);
728        let _ = almost_max + Uint64(12);
729    }
730
731    #[test]
732    fn uint64_multiply_ratio_works() {
733        let base = Uint64(500);
734
735        // factor 1/1
736        assert_eq!(base.multiply_ratio(1u64, 1u64), base);
737        assert_eq!(base.multiply_ratio(3u64, 3u64), base);
738        assert_eq!(base.multiply_ratio(654321u64, 654321u64), base);
739        assert_eq!(base.multiply_ratio(u64::MAX, u64::MAX), base);
740
741        // factor 3/2
742        assert_eq!(base.multiply_ratio(3u64, 2u64), Uint64(750));
743        assert_eq!(base.multiply_ratio(333333u64, 222222u64), Uint64(750));
744
745        // factor 2/3 (integer devision always floors the result)
746        assert_eq!(base.multiply_ratio(2u64, 3u64), Uint64(333));
747        assert_eq!(base.multiply_ratio(222222u64, 333333u64), Uint64(333));
748
749        // factor 5/6 (integer devision always floors the result)
750        assert_eq!(base.multiply_ratio(5u64, 6u64), Uint64(416));
751        assert_eq!(base.multiply_ratio(100u64, 120u64), Uint64(416));
752    }
753
754    #[test]
755    fn uint64_multiply_ratio_does_not_overflow_when_result_fits() {
756        // Almost max value for Uint64.
757        let base = Uint64(u64::MAX - 9);
758
759        assert_eq!(base.multiply_ratio(2u64, 2u64), base);
760    }
761
762    #[test]
763    #[should_panic]
764    fn uint64_multiply_ratio_panicks_on_overflow() {
765        // Almost max value for Uint64.
766        let base = Uint64(u64::MAX - 9);
767
768        assert_eq!(base.multiply_ratio(2u64, 1u64), base);
769    }
770
771    #[test]
772    #[should_panic(expected = "Denominator must not be zero")]
773    fn uint64_multiply_ratio_panics_for_zero_denominator() {
774        Uint64(500).multiply_ratio(1u64, 0u64);
775    }
776
777    #[test]
778    fn uint64_checked_multiply_ratio_does_not_panic() {
779        assert_eq!(
780            Uint64(500u64).checked_multiply_ratio(1u64, 0u64),
781            Err(CheckedMultiplyRatioError::DivideByZero),
782        );
783        assert_eq!(
784            Uint64(500u64).checked_multiply_ratio(u64::MAX, 1u64),
785            Err(CheckedMultiplyRatioError::Overflow),
786        );
787    }
788
789    #[test]
790    fn sum_works() {
791        let nums = vec![Uint64(17), Uint64(123), Uint64(540), Uint64(82)];
792        let expected = Uint64(762);
793
794        let sum_as_ref: Uint64 = nums.iter().sum();
795        assert_eq!(expected, sum_as_ref);
796
797        let sum_as_owned: Uint64 = nums.into_iter().sum();
798        assert_eq!(expected, sum_as_owned);
799    }
800
801    #[test]
802    fn uint64_methods() {
803        // checked_*
804        assert!(matches!(
805            Uint64::MAX.checked_add(Uint64(1)),
806            Err(OverflowError { .. })
807        ));
808        assert!(matches!(Uint64(1).checked_add(Uint64(1)), Ok(Uint64(2))));
809        assert!(matches!(
810            Uint64(0).checked_sub(Uint64(1)),
811            Err(OverflowError { .. })
812        ));
813        assert!(matches!(Uint64(2).checked_sub(Uint64(1)), Ok(Uint64(1))));
814        assert!(matches!(
815            Uint64::MAX.checked_mul(Uint64(2)),
816            Err(OverflowError { .. })
817        ));
818        assert!(matches!(Uint64(2).checked_mul(Uint64(2)), Ok(Uint64(4))));
819        assert!(matches!(
820            Uint64::MAX.checked_pow(2u32),
821            Err(OverflowError { .. })
822        ));
823        assert!(matches!(Uint64(2).checked_pow(3), Ok(Uint64(8))));
824        assert!(matches!(
825            Uint64::MAX.checked_div(Uint64(0)),
826            Err(DivideByZeroError { .. })
827        ));
828        assert!(matches!(Uint64(6).checked_div(Uint64(2)), Ok(Uint64(3))));
829        assert!(matches!(
830            Uint64::MAX.checked_div_euclid(Uint64(0)),
831            Err(DivideByZeroError { .. })
832        ));
833        assert!(matches!(
834            Uint64(6).checked_div_euclid(Uint64(2)),
835            Ok(Uint64(3)),
836        ));
837        assert!(matches!(
838            Uint64::MAX.checked_rem(Uint64(0)),
839            Err(DivideByZeroError { .. })
840        ));
841        assert!(matches!(Uint64(7).checked_rem(Uint64(2)), Ok(Uint64(1))));
842
843        // saturating_*
844        assert_eq!(Uint64::MAX.saturating_add(Uint64(1)), Uint64::MAX);
845        assert_eq!(Uint64(0).saturating_sub(Uint64(1)), Uint64(0));
846        assert_eq!(Uint64::MAX.saturating_mul(Uint64(2)), Uint64::MAX);
847        assert_eq!(Uint64::MAX.saturating_pow(2), Uint64::MAX);
848    }
849
850    #[test]
851    fn uint64_wrapping_methods() {
852        // wrapping_add
853        assert_eq!(Uint64(2).wrapping_add(Uint64(2)), Uint64(4)); // non-wrapping
854        assert_eq!(Uint64::MAX.wrapping_add(Uint64(1)), Uint64(0)); // wrapping
855
856        // wrapping_sub
857        assert_eq!(Uint64(7).wrapping_sub(Uint64(5)), Uint64(2)); // non-wrapping
858        assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64::MAX); // wrapping
859
860        // wrapping_mul
861        assert_eq!(Uint64(3).wrapping_mul(Uint64(2)), Uint64(6)); // non-wrapping
862        assert_eq!(
863            Uint64::MAX.wrapping_mul(Uint64(2)),
864            Uint64::MAX - Uint64::one()
865        ); // wrapping
866
867        // wrapping_pow
868        assert_eq!(Uint64(2).wrapping_pow(3), Uint64(8)); // non-wrapping
869        assert_eq!(Uint64::MAX.wrapping_pow(2), Uint64(1)); // wrapping
870    }
871
872    #[test]
873    #[allow(clippy::op_ref)]
874    fn uint64_implements_rem() {
875        let a = Uint64::new(10);
876        assert_eq!(a % Uint64::new(10), Uint64::zero());
877        assert_eq!(a % Uint64::new(2), Uint64::zero());
878        assert_eq!(a % Uint64::new(1), Uint64::zero());
879        assert_eq!(a % Uint64::new(3), Uint64::new(1));
880        assert_eq!(a % Uint64::new(4), Uint64::new(2));
881
882        // works for refs
883        let a = Uint64::new(10);
884        let b = Uint64::new(3);
885        let expected = Uint64::new(1);
886        assert_eq!(a % b, expected);
887        assert_eq!(a % &b, expected);
888        assert_eq!(&a % b, expected);
889        assert_eq!(&a % &b, expected);
890    }
891
892    #[test]
893    #[should_panic(expected = "divisor of zero")]
894    fn uint64_rem_panics_for_zero() {
895        let _ = Uint64::new(10) % Uint64::zero();
896    }
897
898    #[test]
899    #[allow(clippy::op_ref)]
900    fn uint64_rem_works() {
901        assert_eq!(
902            Uint64::from(12u32) % Uint64::from(10u32),
903            Uint64::from(2u32)
904        );
905        assert_eq!(Uint64::from(50u32) % Uint64::from(5u32), Uint64::zero());
906
907        // works for refs
908        let a = Uint64::from(42u32);
909        let b = Uint64::from(5u32);
910        let expected = Uint64::from(2u32);
911        assert_eq!(a % b, expected);
912        assert_eq!(a % &b, expected);
913        assert_eq!(&a % b, expected);
914        assert_eq!(&a % &b, expected);
915    }
916
917    #[test]
918    fn uint64_rem_assign_works() {
919        let mut a = Uint64::from(30u32);
920        a %= Uint64::from(4u32);
921        assert_eq!(a, Uint64::from(2u32));
922
923        // works for refs
924        let mut a = Uint64::from(25u32);
925        let b = Uint64::from(6u32);
926        a %= &b;
927        assert_eq!(a, Uint64::from(1u32));
928    }
929
930    #[test]
931    fn uint64_abs_diff_works() {
932        let a = Uint64::from(42u32);
933        let b = Uint64::from(5u32);
934        let expected = Uint64::from(37u32);
935        assert_eq!(a.abs_diff(b), expected);
936        assert_eq!(b.abs_diff(a), expected);
937    }
938
939    #[test]
940    fn uint64_partial_eq() {
941        let test_cases = [(1, 1, true), (42, 42, true), (42, 24, false), (0, 0, true)]
942            .into_iter()
943            .map(|(lhs, rhs, expected)| (Uint64::new(lhs), Uint64::new(rhs), expected));
944
945        #[allow(clippy::op_ref)]
946        for (lhs, rhs, expected) in test_cases {
947            assert_eq!(lhs == rhs, expected);
948            assert_eq!(&lhs == rhs, expected);
949            assert_eq!(lhs == &rhs, expected);
950            assert_eq!(&lhs == &rhs, expected);
951        }
952    }
953}