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(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
317primitive_to_wrapped_int!(u8, Uint64);
324primitive_to_wrapped_int!(u16, Uint64);
325primitive_to_wrapped_int!(u32, Uint64);
326primitive_to_wrapped_int!(u64, Uint64);
327
328wrapped_int_to_primitive!(Uint64, u64);
330wrapped_int_to_primitive!(Uint64, u128);
331
332forward_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 #[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 let original = [0; 8];
583 let num = Uint64::from_be_bytes(original);
584 assert!(num.is_zero());
585
586 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 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 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 let original = [0; 8];
612 let num = Uint64::from_le_bytes(original);
613 assert!(num.is_zero());
614
615 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 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 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 let a = Uint64::from(123u64);
696 assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
697
698 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 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 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 assert_eq!((b.checked_sub(a)).unwrap(), Uint64(11111));
769
770 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 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 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 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 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 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 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 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 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 assert_eq!(base.multiply_ratio(3u64, 2u64), Uint64(750));
905 assert_eq!(base.multiply_ratio(333333u64, 222222u64), Uint64(750));
906
907 assert_eq!(base.multiply_ratio(2u64, 3u64), Uint64(333));
909 assert_eq!(base.multiply_ratio(222222u64, 333333u64), Uint64(333));
910
911 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 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 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 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 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 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!(
1059 Uint64::MAX.wrapping_mul(Uint64(2)),
1060 Uint64::MAX - Uint64::one()
1061 ); assert_eq!(Uint64(2).wrapping_pow(3), Uint64(8)); assert_eq!(Uint64::MAX.wrapping_pow(2), Uint64(1)); }
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 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 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 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); 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); 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); 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); 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); 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); 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); 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); 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}