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#[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 #[inline]
66 #[must_use]
67 pub const fn new(value: u64) -> Self {
68 Uint64(value)
69 }
70
71 #[inline]
73 pub const fn zero() -> Self {
74 Uint64(0)
75 }
76
77 #[inline]
79 pub const fn one() -> Self {
80 Self(1)
81 }
82
83 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 #[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 #[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 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 #[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 #[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 #[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
321primitive_to_wrapped_int!(u8, Uint64);
328primitive_to_wrapped_int!(u16, Uint64);
329primitive_to_wrapped_int!(u32, Uint64);
330primitive_to_wrapped_int!(u64, Uint64);
331
332wrapped_int_to_primitive!(Uint64, u64);
334wrapped_int_to_primitive!(Uint64, u128);
335
336forward_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 #[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 let original = [0; 8];
587 let num = Uint64::from_be_bytes(original);
588 assert!(num.is_zero());
589
590 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 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 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 let original = [0; 8];
616 let num = Uint64::from_le_bytes(original);
617 assert!(num.is_zero());
618
619 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 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 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 let a = Uint64::from(123u64);
700 assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
701
702 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 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 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 assert_eq!((b.checked_sub(a)).unwrap(), Uint64(11111));
773
774 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 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 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 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 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 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 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 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 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 assert_eq!(base.multiply_ratio(3u64, 2u64), Uint64(750));
909 assert_eq!(base.multiply_ratio(333333u64, 222222u64), Uint64(750));
910
911 assert_eq!(base.multiply_ratio(2u64, 3u64), Uint64(333));
913 assert_eq!(base.multiply_ratio(222222u64, 333333u64), Uint64(333));
914
915 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 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 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 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 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 assert_eq!(Uint64(2).wrapping_add(Uint64(2)), Uint64(4)); assert_eq!(Uint64::MAX.wrapping_add(Uint64(1)), Uint64(0)); assert_eq!(Uint64(7).wrapping_sub(Uint64(5)), Uint64(2)); assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64::MAX); assert_eq!(Uint64(3).wrapping_mul(Uint64(2)), Uint64(6)); assert_eq!(
1063 Uint64::MAX.wrapping_mul(Uint64(2)),
1064 Uint64::MAX - Uint64::one()
1065 ); assert_eq!(Uint64(2).wrapping_pow(3), Uint64(8)); assert_eq!(Uint64::MAX.wrapping_pow(2), Uint64(1)); }
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 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 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 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); 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); 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); 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); 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); 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); 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); 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); 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}