jk_cosmwasm_std/math/
uint512.rs

1use schemars::JsonSchema;
2use serde::{de, ser, Deserialize, Deserializer, Serialize};
3use std::convert::{TryFrom, TryInto};
4use std::fmt;
5use std::iter::Sum;
6use std::ops::{self, Shr};
7use std::str::FromStr;
8
9use crate::errors::{
10    ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, StdError,
11};
12use crate::{Uint128, Uint256, Uint64};
13
14/// This module is purely a workaround that lets us ignore lints for all the code
15/// the `construct_uint!` macro generates.
16#[allow(clippy::all)]
17mod uints {
18    uint::construct_uint! {
19        pub struct U512(8);
20    }
21}
22
23/// Used internally - we don't want to leak this type since we might change
24/// the implementation in the future.
25use uints::U512;
26
27/// An implementation of u512 that is using strings for JSON encoding/decoding,
28/// such that the full u512 range can be used for clients that convert JSON numbers to floats,
29/// like JavaScript and jq.
30///
31/// # Examples
32///
33/// Use `from` to create instances out of primitive uint types or `new` to provide big
34/// endian bytes:
35///
36/// ```
37/// # use cosmwasm_std::Uint512;
38/// let a = Uint512::from(258u128);
39/// let b = Uint512::new([
40///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
41///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
42///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
43///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
44///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
45///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
46///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
47///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
48/// ]);
49/// assert_eq!(a, b);
50/// ```
51#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
52pub struct Uint512(#[schemars(with = "String")] U512);
53
54impl Uint512 {
55    pub const MAX: Uint512 = Uint512(U512::MAX);
56
57    /// Creates a Uint512(value) from a big endian representation. It's just an alias for
58    /// `from_big_endian`.
59    pub fn new(value: [u8; 64]) -> Self {
60        Self::from_be_bytes(value)
61    }
62
63    /// Creates a Uint512(0)
64    pub const fn zero() -> Self {
65        Uint512(U512::zero())
66    }
67
68    pub fn from_be_bytes(value: [u8; 64]) -> Self {
69        Uint512(U512::from_big_endian(&value))
70    }
71
72    pub fn from_le_bytes(value: [u8; 64]) -> Self {
73        Uint512(U512::from_little_endian(&value))
74    }
75
76    /// Returns a copy of the number as big endian bytes.
77    pub fn to_be_bytes(self) -> [u8; 64] {
78        let mut result = [0u8; 64];
79        self.0.to_big_endian(&mut result);
80        result
81    }
82
83    /// Returns a copy of the number as little endian bytes.
84    pub fn to_le_bytes(self) -> [u8; 64] {
85        let mut result = [0u8; 64];
86        self.0.to_little_endian(&mut result);
87        result
88    }
89
90    pub fn is_zero(&self) -> bool {
91        self.0.is_zero()
92    }
93
94    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
95        self.0
96            .checked_add(other.0)
97            .map(Self)
98            .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other))
99    }
100
101    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
102        self.0
103            .checked_sub(other.0)
104            .map(Self)
105            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other))
106    }
107
108    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
109        self.0
110            .checked_mul(other.0)
111            .map(Self)
112            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other))
113    }
114
115    pub fn checked_div(self, other: Self) -> Result<Self, DivideByZeroError> {
116        self.0
117            .checked_div(other.0)
118            .map(Self)
119            .ok_or_else(|| DivideByZeroError::new(self))
120    }
121
122    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
123        self.0
124            .checked_rem(other.0)
125            .map(Self)
126            .ok_or_else(|| DivideByZeroError::new(self))
127    }
128
129    pub fn checked_shr(self, other: u32) -> Result<Self, OverflowError> {
130        if other >= 512 {
131            return Err(OverflowError::new(OverflowOperation::Shr, self, other));
132        }
133
134        Ok(Self(self.0.shr(other)))
135    }
136
137    pub fn saturating_add(self, other: Self) -> Self {
138        Self(self.0.saturating_add(other.0))
139    }
140
141    pub fn saturating_sub(self, other: Self) -> Self {
142        Self(self.0.saturating_sub(other.0))
143    }
144
145    pub fn saturating_mul(self, other: Self) -> Self {
146        Self(self.0.saturating_mul(other.0))
147    }
148}
149
150impl From<Uint256> for Uint512 {
151    fn from(val: Uint256) -> Self {
152        let bytes = [[0u8; 32], val.to_be_bytes()].concat();
153
154        Self::from_be_bytes(bytes.try_into().unwrap())
155    }
156}
157
158impl From<Uint128> for Uint512 {
159    fn from(val: Uint128) -> Self {
160        val.u128().into()
161    }
162}
163
164impl From<Uint64> for Uint512 {
165    fn from(val: Uint64) -> Self {
166        val.u64().into()
167    }
168}
169
170impl From<u128> for Uint512 {
171    fn from(val: u128) -> Self {
172        Uint512(val.into())
173    }
174}
175
176impl From<u64> for Uint512 {
177    fn from(val: u64) -> Self {
178        Uint512(val.into())
179    }
180}
181
182impl From<u32> for Uint512 {
183    fn from(val: u32) -> Self {
184        Uint512(val.into())
185    }
186}
187
188impl From<u16> for Uint512 {
189    fn from(val: u16) -> Self {
190        Uint512(val.into())
191    }
192}
193
194impl From<u8> for Uint512 {
195    fn from(val: u8) -> Self {
196        Uint512(val.into())
197    }
198}
199
200impl TryFrom<Uint512> for Uint256 {
201    type Error = ConversionOverflowError;
202
203    fn try_from(value: Uint512) -> Result<Self, Self::Error> {
204        let bytes = value.to_be_bytes();
205        let (first_bytes, last_bytes) = bytes.split_at(32);
206
207        if first_bytes != [0u8; 32] {
208            return Err(ConversionOverflowError::new(
209                "Uint512",
210                "Uint256",
211                value.to_string(),
212            ));
213        }
214
215        Ok(Self::from_be_bytes(last_bytes.try_into().unwrap()))
216    }
217}
218
219impl TryFrom<Uint512> for Uint128 {
220    type Error = ConversionOverflowError;
221
222    fn try_from(value: Uint512) -> Result<Self, Self::Error> {
223        Ok(Uint128::new(value.0.try_into().map_err(|_| {
224            ConversionOverflowError::new("Uint512", "Uint128", value.to_string())
225        })?))
226    }
227}
228
229impl TryFrom<&str> for Uint512 {
230    type Error = StdError;
231
232    fn try_from(val: &str) -> Result<Self, Self::Error> {
233        Self::from_str(val)
234    }
235}
236
237impl FromStr for Uint512 {
238    type Err = StdError;
239
240    fn from_str(s: &str) -> Result<Self, Self::Err> {
241        match U512::from_dec_str(s) {
242            Ok(u) => Ok(Self(u)),
243            Err(e) => Err(StdError::generic_err(format!("Parsing u512: {}", e))),
244        }
245    }
246}
247
248impl From<Uint512> for String {
249    fn from(original: Uint512) -> Self {
250        original.to_string()
251    }
252}
253
254impl fmt::Display for Uint512 {
255    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256        // The inner type doesn't work as expected with padding, so we
257        // work around that.
258        let unpadded = self.0.to_string();
259
260        f.pad_integral(true, "", &unpadded)
261    }
262}
263
264impl ops::Add<Uint512> for Uint512 {
265    type Output = Self;
266
267    fn add(self, rhs: Self) -> Self {
268        Uint512(self.0.checked_add(rhs.0).unwrap())
269    }
270}
271
272impl<'a> ops::Add<&'a Uint512> for Uint512 {
273    type Output = Self;
274
275    fn add(self, rhs: &'a Uint512) -> Self {
276        Uint512(self.0.checked_add(rhs.0).unwrap())
277    }
278}
279
280impl ops::Sub<Uint512> for Uint512 {
281    type Output = Self;
282
283    fn sub(self, rhs: Self) -> Self {
284        Uint512(self.0.checked_sub(rhs.0).unwrap())
285    }
286}
287
288impl<'a> ops::Sub<&'a Uint512> for Uint512 {
289    type Output = Self;
290
291    fn sub(self, rhs: &'a Uint512) -> Self {
292        Uint512(self.0.checked_sub(rhs.0).unwrap())
293    }
294}
295
296impl ops::Div<Uint512> for Uint512 {
297    type Output = Self;
298
299    fn div(self, rhs: Self) -> Self::Output {
300        Self(self.0.checked_div(rhs.0).unwrap())
301    }
302}
303
304impl<'a> ops::Div<&'a Uint512> for Uint512 {
305    type Output = Self;
306
307    fn div(self, rhs: &'a Uint512) -> Self::Output {
308        Self(self.0.checked_div(rhs.0).unwrap())
309    }
310}
311
312impl ops::Mul<Uint512> for Uint512 {
313    type Output = Self;
314
315    fn mul(self, rhs: Self) -> Self::Output {
316        Self(self.0.checked_mul(rhs.0).unwrap())
317    }
318}
319
320impl<'a> ops::Mul<&'a Uint512> for Uint512 {
321    type Output = Self;
322
323    fn mul(self, rhs: &'a Uint512) -> Self::Output {
324        Self(self.0.checked_mul(rhs.0).unwrap())
325    }
326}
327
328impl ops::Shr<u32> for Uint512 {
329    type Output = Self;
330
331    fn shr(self, rhs: u32) -> Self::Output {
332        self.checked_shr(rhs).unwrap_or_else(|_| {
333            panic!(
334                "right shift error: {} is larger or equal than the number of bits in Uint512",
335                rhs,
336            )
337        })
338    }
339}
340
341impl<'a> ops::Shr<&'a u32> for Uint512 {
342    type Output = Self;
343
344    fn shr(self, rhs: &'a u32) -> Self::Output {
345        Shr::<u32>::shr(self, *rhs)
346    }
347}
348
349impl ops::AddAssign<Uint512> for Uint512 {
350    fn add_assign(&mut self, rhs: Uint512) {
351        self.0 = self.0.checked_add(rhs.0).unwrap();
352    }
353}
354
355impl<'a> ops::AddAssign<&'a Uint512> for Uint512 {
356    fn add_assign(&mut self, rhs: &'a Uint512) {
357        self.0 = self.0.checked_add(rhs.0).unwrap();
358    }
359}
360
361impl ops::SubAssign<Uint512> for Uint512 {
362    fn sub_assign(&mut self, rhs: Uint512) {
363        self.0 = self.0.checked_sub(rhs.0).unwrap();
364    }
365}
366
367impl<'a> ops::SubAssign<&'a Uint512> for Uint512 {
368    fn sub_assign(&mut self, rhs: &'a Uint512) {
369        self.0 = self.0.checked_sub(rhs.0).unwrap();
370    }
371}
372
373impl ops::DivAssign<Uint512> for Uint512 {
374    fn div_assign(&mut self, rhs: Self) {
375        self.0 = self.0.checked_div(rhs.0).unwrap();
376    }
377}
378
379impl<'a> ops::DivAssign<&'a Uint512> for Uint512 {
380    fn div_assign(&mut self, rhs: &'a Uint512) {
381        self.0 = self.0.checked_div(rhs.0).unwrap();
382    }
383}
384
385impl ops::MulAssign<Uint512> for Uint512 {
386    fn mul_assign(&mut self, rhs: Self) {
387        self.0 = self.0.checked_mul(rhs.0).unwrap();
388    }
389}
390
391impl<'a> ops::MulAssign<&'a Uint512> for Uint512 {
392    fn mul_assign(&mut self, rhs: &'a Uint512) {
393        self.0 = self.0.checked_mul(rhs.0).unwrap();
394    }
395}
396
397impl ops::ShrAssign<u32> for Uint512 {
398    fn shr_assign(&mut self, rhs: u32) {
399        *self = Shr::<u32>::shr(*self, rhs);
400    }
401}
402
403impl<'a> ops::ShrAssign<&'a u32> for Uint512 {
404    fn shr_assign(&mut self, rhs: &'a u32) {
405        *self = Shr::<u32>::shr(*self, *rhs);
406    }
407}
408
409impl Serialize for Uint512 {
410    /// Serializes as an integer string using base 10
411    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
412    where
413        S: ser::Serializer,
414    {
415        serializer.serialize_str(&self.to_string())
416    }
417}
418
419impl<'de> Deserialize<'de> for Uint512 {
420    /// Deserialized from an integer string using base 10
421    fn deserialize<D>(deserializer: D) -> Result<Uint512, D::Error>
422    where
423        D: Deserializer<'de>,
424    {
425        deserializer.deserialize_str(Uint512Visitor)
426    }
427}
428
429struct Uint512Visitor;
430
431impl<'de> de::Visitor<'de> for Uint512Visitor {
432    type Value = Uint512;
433
434    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
435        formatter.write_str("string-encoded integer")
436    }
437
438    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
439    where
440        E: de::Error,
441    {
442        Uint512::try_from(v).map_err(|e| E::custom(format!("invalid Uint512 '{}' - {}", v, e)))
443    }
444}
445
446impl Sum<Uint512> for Uint512 {
447    fn sum<I: Iterator<Item = Uint512>>(iter: I) -> Self {
448        iter.fold(Uint512::zero(), ops::Add::add)
449    }
450}
451
452impl<'a> Sum<&'a Uint512> for Uint512 {
453    fn sum<I: Iterator<Item = &'a Uint512>>(iter: I) -> Self {
454        iter.fold(Uint512::zero(), ops::Add::add)
455    }
456}
457
458#[cfg(test)]
459mod tests {
460    use super::*;
461    use crate::{from_slice, to_vec};
462
463    #[test]
464    fn uint512_construct() {
465        let num = Uint512::new([1; 64]);
466        let a: [u8; 64] = num.to_be_bytes();
467        assert_eq!(a, [1; 64]);
468
469        let be_bytes = [
470            0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
471            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
472            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
473            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
474        ];
475        let num = Uint512::new(be_bytes);
476        let resulting_bytes: [u8; 64] = num.to_be_bytes();
477        assert_eq!(be_bytes, resulting_bytes);
478    }
479
480    #[test]
481    fn uint512_endianness() {
482        let be_bytes = [
483            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
484            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
485            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
486            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
487        ];
488        let le_bytes = [
489            3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
490            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
491            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
492            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
493        ];
494
495        // These should all be the same.
496        let num1 = Uint512::new(be_bytes);
497        let num2 = Uint512::from_be_bytes(be_bytes);
498        let num3 = Uint512::from_le_bytes(le_bytes);
499        assert_eq!(num1, Uint512::from(65536u32 + 512 + 3));
500        assert_eq!(num1, num2);
501        assert_eq!(num1, num3);
502    }
503
504    #[test]
505    fn uint512_convert_from() {
506        let a = Uint512::from(5u128);
507        assert_eq!(a.0, U512::from(5));
508
509        let a = Uint512::from(5u64);
510        assert_eq!(a.0, U512::from(5));
511
512        let a = Uint512::from(5u32);
513        assert_eq!(a.0, U512::from(5));
514
515        let a = Uint512::from(5u16);
516        assert_eq!(a.0, U512::from(5));
517
518        let a = Uint512::from(5u8);
519        assert_eq!(a.0, U512::from(5));
520
521        let result = Uint512::try_from("34567");
522        assert_eq!(result.unwrap().0, U512::from_dec_str("34567").unwrap());
523
524        let result = Uint512::try_from("1.23");
525        assert!(result.is_err());
526    }
527
528    #[test]
529    fn uint512_convert_to_uint128() {
530        let source = Uint512::from(42u128);
531        let target = Uint128::try_from(source);
532        assert_eq!(target, Ok(Uint128::new(42u128)));
533
534        let source = Uint512::MAX;
535        let target = Uint128::try_from(source);
536        assert_eq!(
537            target,
538            Err(ConversionOverflowError::new(
539                "Uint512",
540                "Uint128",
541                Uint512::MAX.to_string()
542            ))
543        );
544    }
545
546    #[test]
547    fn uint512_implements_display() {
548        let a = Uint512::from(12345u32);
549        assert_eq!(format!("Embedded: {}", a), "Embedded: 12345");
550        assert_eq!(a.to_string(), "12345");
551
552        let a = Uint512::zero();
553        assert_eq!(format!("Embedded: {}", a), "Embedded: 0");
554        assert_eq!(a.to_string(), "0");
555    }
556
557    #[test]
558    fn uint512_display_padding_works() {
559        let a = Uint512::from(123u64);
560        assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123");
561    }
562
563    #[test]
564    fn uint512_is_zero_works() {
565        assert!(Uint512::zero().is_zero());
566        assert!(Uint512(U512::from(0)).is_zero());
567
568        assert!(!Uint512::from(1u32).is_zero());
569        assert!(!Uint512::from(123u32).is_zero());
570    }
571
572    #[test]
573    fn uint512_json() {
574        let orig = Uint512::from(1234567890987654321u128);
575        let serialized = to_vec(&orig).unwrap();
576        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
577        let parsed: Uint512 = from_slice(&serialized).unwrap();
578        assert_eq!(parsed, orig);
579    }
580
581    #[test]
582    fn uint512_compare() {
583        let a = Uint512::from(12345u32);
584        let b = Uint512::from(23456u32);
585
586        assert!(a < b);
587        assert!(b > a);
588        assert_eq!(a, Uint512::from(12345u32));
589    }
590
591    #[test]
592    #[allow(clippy::op_ref)]
593    fn uint512_math() {
594        let a = Uint512::from(12345u32);
595        let b = Uint512::from(23456u32);
596
597        // test + with owned and reference right hand side
598        assert_eq!(a + b, Uint512::from(35801u32));
599        assert_eq!(a + &b, Uint512::from(35801u32));
600
601        // test - with owned and reference right hand side
602        assert_eq!(b - a, Uint512::from(11111u32));
603        assert_eq!(b - &a, Uint512::from(11111u32));
604
605        // test += with owned and reference right hand side
606        let mut c = Uint512::from(300000u32);
607        c += b;
608        assert_eq!(c, Uint512::from(323456u32));
609        let mut d = Uint512::from(300000u32);
610        d += &b;
611        assert_eq!(d, Uint512::from(323456u32));
612
613        // test -= with owned and reference right hand side
614        let mut c = Uint512::from(300000u32);
615        c -= b;
616        assert_eq!(c, Uint512::from(276544u32));
617        let mut d = Uint512::from(300000u32);
618        d -= &b;
619        assert_eq!(d, Uint512::from(276544u32));
620
621        // error result on underflow (- would produce negative result)
622        let underflow_result = a.checked_sub(b);
623        let OverflowError {
624            operand1, operand2, ..
625        } = underflow_result.unwrap_err();
626        assert_eq!((operand1, operand2), (a.to_string(), b.to_string()));
627    }
628
629    #[test]
630    #[should_panic]
631    fn uint512_add_overflow_panics() {
632        let max = Uint512::new([255u8; 64]);
633        let _ = max + Uint512::from(12u32);
634    }
635
636    #[test]
637    #[should_panic]
638    fn uint512_sub_overflow_panics() {
639        let _ = Uint512::from(1u32) - Uint512::from(2u32);
640    }
641
642    #[test]
643    fn uint512_shr_works() {
644        let original = Uint512::new([
645            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
646            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
647            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
648            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8,
649        ]);
650
651        let shifted = Uint512::new([
652            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
653            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
654            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
655            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8,
656        ]);
657
658        assert_eq!(original >> 2u32, shifted);
659    }
660
661    #[test]
662    #[should_panic]
663    fn uint512_shr_overflow_panics() {
664        let _ = Uint512::from(1u32) >> 512u32;
665    }
666
667    #[test]
668    fn sum_works() {
669        let nums = vec![
670            Uint512::from(17u32),
671            Uint512::from(123u32),
672            Uint512::from(540u32),
673            Uint512::from(82u32),
674        ];
675        let expected = Uint512::from(762u32);
676
677        let sum_as_ref = nums.iter().sum();
678        assert_eq!(expected, sum_as_ref);
679
680        let sum_as_owned = nums.into_iter().sum();
681        assert_eq!(expected, sum_as_owned);
682    }
683
684    #[test]
685    fn uint512_methods() {
686        // checked_*
687        assert!(matches!(
688            Uint512::MAX.checked_add(Uint512::from(1u32)),
689            Err(OverflowError { .. })
690        ));
691        assert!(matches!(
692            Uint512::from(0u32).checked_sub(Uint512::from(1u32)),
693            Err(OverflowError { .. })
694        ));
695        assert!(matches!(
696            Uint512::MAX.checked_mul(Uint512::from(2u32)),
697            Err(OverflowError { .. })
698        ));
699        assert!(matches!(
700            Uint512::MAX.checked_div(Uint512::from(0u32)),
701            Err(DivideByZeroError { .. })
702        ));
703        assert!(matches!(
704            Uint512::MAX.checked_rem(Uint512::from(0u32)),
705            Err(DivideByZeroError { .. })
706        ));
707
708        // saturating_*
709        assert_eq!(
710            Uint512::MAX.saturating_add(Uint512::from(1u32)),
711            Uint512::MAX
712        );
713        assert_eq!(
714            Uint512::from(0u32).saturating_sub(Uint512::from(1u32)),
715            Uint512::from(0u32)
716        );
717        assert_eq!(
718            Uint512::MAX.saturating_mul(Uint512::from(2u32)),
719            Uint512::MAX
720        );
721    }
722}