cosmwasm_std/math/
int512.rs

1use alloc::string::{String, ToString};
2use core::fmt;
3use core::ops::{
4    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr,
5    ShrAssign, Sub, SubAssign,
6};
7use core::str::FromStr;
8
9use crate::errors::{DivideByZeroError, DivisionError, OverflowError, OverflowOperation, StdError};
10use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
11use crate::{
12    Int128, Int256, Int64, Uint128, Uint256, Uint512, Uint64, __internal::forward_ref_partial_eq,
13};
14
15/// Used internally - we don't want to leak this type since we might change
16/// the implementation in the future.
17use bnum::types::{I512, U512};
18
19use super::conversion::{grow_be_int, primitive_to_wrapped_int, try_from_uint_to_int};
20use super::impl_int_serde;
21use super::num_consts::NumConsts;
22
23/// An implementation of i512 that is using strings for JSON encoding/decoding,
24/// such that the full i512 range can be used for clients that convert JSON numbers to floats,
25/// like JavaScript and jq.
26///
27/// # Examples
28///
29/// Use `new` to create instances out of i128, `from` for other primitive uint/int types
30/// or `from_be_bytes` to provide big endian bytes:
31///
32/// ```
33/// # use cosmwasm_std::Int512;
34/// let a = Int512::new(258i128);
35/// let b = Int512::from(258u128);
36/// let c = Int512::from_be_bytes([
37///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
38///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
39///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
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, 1u8, 2u8,
45/// ]);
46/// assert_eq!(a, b);
47/// assert_eq!(a, c);
48/// ```
49#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, schemars::JsonSchema)]
50pub struct Int512(#[schemars(with = "String")] pub(crate) I512);
51
52impl_int_serde!(Int512);
53forward_ref_partial_eq!(Int512, Int512);
54
55impl Int512 {
56    pub const MAX: Int512 = Int512(I512::MAX);
57    pub const MIN: Int512 = Int512(I512::MIN);
58
59    /// Creates a Int512(value).
60    ///
61    /// This method is less flexible than `from` but can be called in a const context.
62    ///
63    /// Before CosmWasm 3 this took a byte array as an argument. You can get this behaviour
64    /// with [`from_be_bytes`].
65    ///
66    /// [`from_be_bytes`]: Self::from_be_bytes
67    #[inline]
68    #[must_use]
69    pub const fn new(value: i128) -> Self {
70        Self::from_be_bytes(grow_be_int(value.to_be_bytes()))
71    }
72
73    /// Creates a Int512(0)
74    #[inline]
75    pub const fn zero() -> Self {
76        Int512(I512::ZERO)
77    }
78
79    /// Creates a Int512(1)
80    #[inline]
81    pub const fn one() -> Self {
82        Self(I512::ONE)
83    }
84
85    #[must_use]
86    pub const fn from_be_bytes(data: [u8; 64]) -> Self {
87        let words: [u64; 8] = [
88            u64::from_le_bytes([
89                data[63], data[62], data[61], data[60], data[59], data[58], data[57], data[56],
90            ]),
91            u64::from_le_bytes([
92                data[55], data[54], data[53], data[52], data[51], data[50], data[49], data[48],
93            ]),
94            u64::from_le_bytes([
95                data[47], data[46], data[45], data[44], data[43], data[42], data[41], data[40],
96            ]),
97            u64::from_le_bytes([
98                data[39], data[38], data[37], data[36], data[35], data[34], data[33], data[32],
99            ]),
100            u64::from_le_bytes([
101                data[31], data[30], data[29], data[28], data[27], data[26], data[25], data[24],
102            ]),
103            u64::from_le_bytes([
104                data[23], data[22], data[21], data[20], data[19], data[18], data[17], data[16],
105            ]),
106            u64::from_le_bytes([
107                data[15], data[14], data[13], data[12], data[11], data[10], data[9], data[8],
108            ]),
109            u64::from_le_bytes([
110                data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0],
111            ]),
112        ];
113        Self(I512::from_bits(U512::from_digits(words)))
114    }
115
116    #[must_use]
117    pub const fn from_le_bytes(data: [u8; 64]) -> Self {
118        let words: [u64; 8] = [
119            u64::from_le_bytes([
120                data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
121            ]),
122            u64::from_le_bytes([
123                data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
124            ]),
125            u64::from_le_bytes([
126                data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
127            ]),
128            u64::from_le_bytes([
129                data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
130            ]),
131            u64::from_le_bytes([
132                data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39],
133            ]),
134            u64::from_le_bytes([
135                data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47],
136            ]),
137            u64::from_le_bytes([
138                data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55],
139            ]),
140            u64::from_le_bytes([
141                data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63],
142            ]),
143        ];
144        Self(I512::from_bits(U512::from_digits(words)))
145    }
146
147    /// Returns a copy of the number as big endian bytes.
148    #[must_use = "this returns the result of the operation, without modifying the original"]
149    pub const fn to_be_bytes(self) -> [u8; 64] {
150        let bits = self.0.to_bits();
151        let words = bits.digits();
152        let words = [
153            words[7].to_be_bytes(),
154            words[6].to_be_bytes(),
155            words[5].to_be_bytes(),
156            words[4].to_be_bytes(),
157            words[3].to_be_bytes(),
158            words[2].to_be_bytes(),
159            words[1].to_be_bytes(),
160            words[0].to_be_bytes(),
161        ];
162        unsafe { core::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }
163    }
164
165    /// Returns a copy of the number as little endian bytes.
166    #[must_use = "this returns the result of the operation, without modifying the original"]
167    pub const fn to_le_bytes(self) -> [u8; 64] {
168        let bits = self.0.to_bits();
169        let words = bits.digits();
170        let words = [
171            words[0].to_le_bytes(),
172            words[1].to_le_bytes(),
173            words[2].to_le_bytes(),
174            words[3].to_le_bytes(),
175            words[4].to_le_bytes(),
176            words[5].to_le_bytes(),
177            words[6].to_le_bytes(),
178            words[7].to_le_bytes(),
179        ];
180        unsafe { core::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }
181    }
182
183    #[must_use]
184    pub const fn is_zero(&self) -> bool {
185        self.0.is_zero()
186    }
187
188    #[must_use]
189    pub const fn is_negative(&self) -> bool {
190        self.0.is_negative()
191    }
192
193    #[must_use = "this returns the result of the operation, without modifying the original"]
194    pub const fn pow(self, exp: u32) -> Self {
195        match self.0.checked_pow(exp) {
196            Some(val) => Self(val),
197            None => panic!("attempt to exponentiate with overflow"),
198        }
199    }
200
201    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
202        self.0
203            .checked_add(other.0)
204            .map(Self)
205            .ok_or_else(|| OverflowError::new(OverflowOperation::Add))
206    }
207
208    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
209        self.0
210            .checked_sub(other.0)
211            .map(Self)
212            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub))
213    }
214
215    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
216        self.0
217            .checked_mul(other.0)
218            .map(Self)
219            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul))
220    }
221
222    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
223        self.0
224            .checked_pow(exp)
225            .map(Self)
226            .ok_or_else(|| OverflowError::new(OverflowOperation::Pow))
227    }
228
229    pub fn checked_div(self, other: Self) -> Result<Self, DivisionError> {
230        if other.is_zero() {
231            return Err(DivisionError::DivideByZero);
232        }
233        self.0
234            .checked_div(other.0)
235            .map(Self)
236            .ok_or(DivisionError::Overflow)
237    }
238
239    pub fn checked_div_euclid(self, other: Self) -> Result<Self, DivisionError> {
240        if other.is_zero() {
241            return Err(DivisionError::DivideByZero);
242        }
243        self.0
244            .checked_div_euclid(other.0)
245            .map(Self)
246            .ok_or(DivisionError::Overflow)
247    }
248
249    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
250        self.0
251            .checked_rem(other.0)
252            .map(Self)
253            .ok_or(DivideByZeroError)
254    }
255
256    pub fn checked_shr(self, other: u32) -> Result<Self, OverflowError> {
257        if other >= 512 {
258            return Err(OverflowError::new(OverflowOperation::Shr));
259        }
260
261        Ok(Self(self.0.shr(other)))
262    }
263
264    pub fn checked_shl(self, other: u32) -> Result<Self, OverflowError> {
265        if other >= 512 {
266            return Err(OverflowError::new(OverflowOperation::Shl));
267        }
268
269        Ok(Self(self.0.shl(other)))
270    }
271
272    #[must_use = "this returns the result of the operation, without modifying the original"]
273    #[inline]
274    pub fn wrapping_add(self, other: Self) -> Self {
275        Self(self.0.wrapping_add(other.0))
276    }
277
278    #[must_use = "this returns the result of the operation, without modifying the original"]
279    #[inline]
280    pub fn wrapping_sub(self, other: Self) -> Self {
281        Self(self.0.wrapping_sub(other.0))
282    }
283
284    #[must_use = "this returns the result of the operation, without modifying the original"]
285    #[inline]
286    pub fn wrapping_mul(self, other: Self) -> Self {
287        Self(self.0.wrapping_mul(other.0))
288    }
289
290    #[must_use = "this returns the result of the operation, without modifying the original"]
291    #[inline]
292    pub fn wrapping_pow(self, other: u32) -> Self {
293        Self(self.0.wrapping_pow(other))
294    }
295
296    #[must_use = "this returns the result of the operation, without modifying the original"]
297    pub fn saturating_add(self, other: Self) -> Self {
298        Self(self.0.saturating_add(other.0))
299    }
300
301    #[must_use = "this returns the result of the operation, without modifying the original"]
302    pub fn saturating_sub(self, other: Self) -> Self {
303        Self(self.0.saturating_sub(other.0))
304    }
305
306    #[must_use = "this returns the result of the operation, without modifying the original"]
307    pub fn saturating_mul(self, other: Self) -> Self {
308        Self(self.0.saturating_mul(other.0))
309    }
310
311    #[must_use = "this returns the result of the operation, without modifying the original"]
312    pub fn saturating_pow(self, exp: u32) -> Self {
313        Self(self.0.saturating_pow(exp))
314    }
315
316    #[must_use = "this returns the result of the operation, without modifying the original"]
317    pub const fn abs_diff(self, other: Self) -> Uint512 {
318        Uint512(self.0.abs_diff(other.0))
319    }
320
321    #[must_use = "this returns the result of the operation, without modifying the original"]
322    pub const fn abs(self) -> Self {
323        match self.0.checked_abs() {
324            Some(val) => Self(val),
325            None => panic!("attempt to calculate absolute value with overflow"),
326        }
327    }
328
329    #[must_use = "this returns the result of the operation, without modifying the original"]
330    pub const fn unsigned_abs(self) -> Uint512 {
331        Uint512(self.0.unsigned_abs())
332    }
333
334    /// Strict negation. Computes -self, panicking if self == MIN.
335    ///
336    /// This is the same as [`Int512::neg`] but const.
337    pub const fn strict_neg(self) -> Self {
338        match self.0.checked_neg() {
339            Some(val) => Self(val),
340            None => panic!("attempt to negate with overflow"),
341        }
342    }
343}
344
345impl NumConsts for Int512 {
346    const ZERO: Self = Self::zero();
347    const ONE: Self = Self::one();
348    const MAX: Self = Self::MAX;
349    const MIN: Self = Self::MIN;
350}
351
352// Uint to Int
353try_from_uint_to_int!(Uint512, Int512);
354
355impl From<Uint256> for Int512 {
356    fn from(val: Uint256) -> Self {
357        let mut bytes = [0u8; 64];
358        bytes[32..].copy_from_slice(&val.to_be_bytes());
359
360        Self::from_be_bytes(bytes)
361    }
362}
363
364impl From<Uint128> for Int512 {
365    fn from(val: Uint128) -> Self {
366        val.u128().into()
367    }
368}
369
370impl From<Uint64> for Int512 {
371    fn from(val: Uint64) -> Self {
372        val.u64().into()
373    }
374}
375
376// uint to Int
377primitive_to_wrapped_int!(u8, Int512);
378primitive_to_wrapped_int!(u16, Int512);
379primitive_to_wrapped_int!(u32, Int512);
380primitive_to_wrapped_int!(u64, Int512);
381primitive_to_wrapped_int!(u128, Int512);
382
383// int to Int
384primitive_to_wrapped_int!(i8, Int512);
385primitive_to_wrapped_int!(i16, Int512);
386primitive_to_wrapped_int!(i32, Int512);
387primitive_to_wrapped_int!(i64, Int512);
388primitive_to_wrapped_int!(i128, Int512);
389
390// Int to Int
391impl From<Int64> for Int512 {
392    fn from(val: Int64) -> Self {
393        Int512(val.i64().into())
394    }
395}
396
397impl From<Int128> for Int512 {
398    fn from(val: Int128) -> Self {
399        Int512(val.i128().into())
400    }
401}
402
403impl From<Int256> for Int512 {
404    fn from(val: Int256) -> Self {
405        Self::from_be_bytes(grow_be_int(val.to_be_bytes()))
406    }
407}
408
409impl TryFrom<&str> for Int512 {
410    type Error = StdError;
411
412    fn try_from(val: &str) -> Result<Self, Self::Error> {
413        Self::from_str(val)
414    }
415}
416
417impl FromStr for Int512 {
418    type Err = StdError;
419
420    fn from_str(s: &str) -> Result<Self, Self::Err> {
421        match I512::from_str_radix(s, 10) {
422            Ok(u) => Ok(Self(u)),
423            Err(e) => Err(StdError::generic_err(format!("Parsing Int512: {e}"))),
424        }
425    }
426}
427
428impl From<Int512> for String {
429    fn from(original: Int512) -> Self {
430        original.to_string()
431    }
432}
433
434impl fmt::Display for Int512 {
435    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
436        self.0.fmt(f)
437    }
438}
439
440impl Add<Int512> for Int512 {
441    type Output = Self;
442
443    fn add(self, rhs: Self) -> Self {
444        Int512(self.0.checked_add(rhs.0).unwrap())
445    }
446}
447forward_ref_binop!(impl Add, add for Int512, Int512);
448
449impl Sub<Int512> for Int512 {
450    type Output = Self;
451
452    fn sub(self, rhs: Self) -> Self {
453        Int512(self.0.checked_sub(rhs.0).unwrap())
454    }
455}
456forward_ref_binop!(impl Sub, sub for Int512, Int512);
457
458impl SubAssign<Int512> for Int512 {
459    fn sub_assign(&mut self, rhs: Int512) {
460        self.0 = self.0.checked_sub(rhs.0).unwrap();
461    }
462}
463forward_ref_op_assign!(impl SubAssign, sub_assign for Int512, Int512);
464
465impl Div<Int512> for Int512 {
466    type Output = Self;
467
468    fn div(self, rhs: Self) -> Self::Output {
469        Self(self.0.checked_div(rhs.0).unwrap())
470    }
471}
472forward_ref_binop!(impl Div, div for Int512, Int512);
473
474impl Rem for Int512 {
475    type Output = Self;
476
477    /// # Panics
478    ///
479    /// This operation will panic if `rhs` is zero.
480    #[inline]
481    fn rem(self, rhs: Self) -> Self {
482        Self(self.0.rem(rhs.0))
483    }
484}
485forward_ref_binop!(impl Rem, rem for Int512, Int512);
486
487impl Not for Int512 {
488    type Output = Self;
489
490    fn not(self) -> Self::Output {
491        Self(!self.0)
492    }
493}
494
495impl Neg for Int512 {
496    type Output = Self;
497
498    fn neg(self) -> Self::Output {
499        self.strict_neg()
500    }
501}
502
503impl RemAssign<Int512> for Int512 {
504    fn rem_assign(&mut self, rhs: Int512) {
505        *self = *self % rhs;
506    }
507}
508forward_ref_op_assign!(impl RemAssign, rem_assign for Int512, Int512);
509
510impl Mul<Int512> for Int512 {
511    type Output = Self;
512
513    fn mul(self, rhs: Self) -> Self::Output {
514        Self(self.0.checked_mul(rhs.0).unwrap())
515    }
516}
517forward_ref_binop!(impl Mul, mul for Int512, Int512);
518
519impl MulAssign<Int512> for Int512 {
520    fn mul_assign(&mut self, rhs: Self) {
521        self.0 = self.0.checked_mul(rhs.0).unwrap();
522    }
523}
524forward_ref_op_assign!(impl MulAssign, mul_assign for Int512, Int512);
525
526impl Shr<u32> for Int512 {
527    type Output = Self;
528
529    fn shr(self, rhs: u32) -> Self::Output {
530        self.checked_shr(rhs).unwrap_or_else(|_| {
531            panic!("right shift error: {rhs} is larger or equal than the number of bits in Int512",)
532        })
533    }
534}
535forward_ref_binop!(impl Shr, shr for Int512, u32);
536
537impl Shl<u32> for Int512 {
538    type Output = Self;
539
540    fn shl(self, rhs: u32) -> Self::Output {
541        self.checked_shl(rhs).unwrap_or_else(|_| {
542            panic!("left shift error: {rhs} is larger or equal than the number of bits in Int512",)
543        })
544    }
545}
546forward_ref_binop!(impl Shl, shl for Int512, u32);
547
548impl AddAssign<Int512> for Int512 {
549    fn add_assign(&mut self, rhs: Int512) {
550        self.0 = self.0.checked_add(rhs.0).unwrap();
551    }
552}
553forward_ref_op_assign!(impl AddAssign, add_assign for Int512, Int512);
554
555impl DivAssign<Int512> for Int512 {
556    fn div_assign(&mut self, rhs: Self) {
557        self.0 = self.0.checked_div(rhs.0).unwrap();
558    }
559}
560forward_ref_op_assign!(impl DivAssign, div_assign for Int512, Int512);
561
562impl ShrAssign<u32> for Int512 {
563    fn shr_assign(&mut self, rhs: u32) {
564        *self = Shr::<u32>::shr(*self, rhs);
565    }
566}
567forward_ref_op_assign!(impl ShrAssign, shr_assign for Int512, u32);
568
569impl ShlAssign<u32> for Int512 {
570    fn shl_assign(&mut self, rhs: u32) {
571        *self = Shl::<u32>::shl(*self, rhs);
572    }
573}
574forward_ref_op_assign!(impl ShlAssign, shl_assign for Int512, u32);
575
576impl<A> core::iter::Sum<A> for Int512
577where
578    Self: Add<A, Output = Self>,
579{
580    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
581        iter.fold(Self::zero(), Add::add)
582    }
583}
584
585#[cfg(test)]
586mod tests {
587    use super::*;
588    use crate::math::conversion::test_try_from_uint_to_int;
589
590    #[test]
591    fn size_of_works() {
592        assert_eq!(core::mem::size_of::<Int512>(), 64);
593    }
594
595    #[test]
596    fn int512_new_works() {
597        let num = Int512::new(1);
598        assert_eq!(
599            num.to_be_bytes(),
600            [
601                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
602                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
603                0, 0, 0, 0, 0, 0, 0, 1
604            ]
605        );
606
607        let num = Int512::new(-1);
608        assert_eq!(
609            num.to_be_bytes(),
610            [
611                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
612                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
613                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
614                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
615            ]
616        );
617
618        for v in [0, 1, -4, 18, 875786576, -11763498739, i128::MAX, i128::MIN] {
619            // From is implemented by bnum, so we test two independent implementations against each other
620            let uut = Int512::new(v);
621            assert_eq!(uut, Int512::from(v));
622        }
623    }
624
625    #[test]
626    fn int512_from_be_bytes_works() {
627        let num = Int512::from_be_bytes([1; 64]);
628        let a: [u8; 64] = num.to_be_bytes();
629        assert_eq!(a, [1; 64]);
630
631        let be_bytes = [
632            0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
633            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
634            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
635            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
636        ];
637        let num = Int512::from_be_bytes(be_bytes);
638        let resulting_bytes: [u8; 64] = num.to_be_bytes();
639        assert_eq!(be_bytes, resulting_bytes);
640    }
641
642    #[test]
643    fn int512_not_works() {
644        let num = Int512::from_be_bytes([1; 64]);
645        let a = (!num).to_be_bytes();
646        assert_eq!(a, [254; 64]);
647
648        assert_eq!(!Int512::from(-1234806i128), Int512::from(!-1234806i128));
649
650        assert_eq!(!Int512::MAX, Int512::MIN);
651        assert_eq!(!Int512::MIN, Int512::MAX);
652    }
653
654    #[test]
655    fn int512_zero_works() {
656        let zero = Int512::zero();
657        assert_eq!(zero.to_be_bytes(), [0; 64]);
658    }
659
660    #[test]
661    fn uint512_one_works() {
662        let one = Int512::one();
663        let mut one_be = [0; 64];
664        one_be[63] = 1;
665
666        assert_eq!(one.to_be_bytes(), one_be);
667    }
668
669    #[test]
670    fn int512_endianness() {
671        let be_bytes = [
672            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
673            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
674            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
675            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
676        ];
677        let le_bytes = [
678            3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
679            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
680            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
681            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
682        ];
683
684        // These should all be the same.
685        let a = Int512::from_be_bytes(be_bytes);
686        let b = Int512::from_le_bytes(le_bytes);
687        assert_eq!(a, Int512::from(65536u32 + 512 + 3));
688        assert_eq!(a, b);
689    }
690
691    #[test]
692    fn int512_convert_from() {
693        let a = Int512::from(5u128);
694        assert_eq!(a.0, I512::from(5u32));
695
696        let a = Int512::from(5u64);
697        assert_eq!(a.0, I512::from(5u32));
698
699        let a = Int512::from(5u32);
700        assert_eq!(a.0, I512::from(5u32));
701
702        let a = Int512::from(5u16);
703        assert_eq!(a.0, I512::from(5u32));
704
705        let a = Int512::from(5u8);
706        assert_eq!(a.0, I512::from(5u32));
707
708        let a = Int512::from(-5i128);
709        assert_eq!(a.0, I512::from(-5i32));
710
711        let a = Int512::from(-5i64);
712        assert_eq!(a.0, I512::from(-5i32));
713
714        let a = Int512::from(-5i32);
715        assert_eq!(a.0, I512::from(-5i32));
716
717        let a = Int512::from(-5i16);
718        assert_eq!(a.0, I512::from(-5i32));
719
720        let a = Int512::from(-5i8);
721        assert_eq!(a.0, I512::from(-5i32));
722
723        // other big signed integers
724        let values = [
725            Int64::MAX,
726            Int64::MIN,
727            Int64::one(),
728            -Int64::one(),
729            Int64::zero(),
730        ];
731        for v in values {
732            assert_eq!(Int512::from(v).to_string(), v.to_string());
733        }
734
735        let values = [
736            Int128::MAX,
737            Int128::MIN,
738            Int128::one(),
739            -Int128::one(),
740            Int128::zero(),
741        ];
742        for v in values {
743            assert_eq!(Int512::from(v).to_string(), v.to_string());
744        }
745
746        let values = [
747            Int256::MAX,
748            Int256::MIN,
749            Int256::one(),
750            -Int256::one(),
751            Int256::zero(),
752        ];
753        for v in values {
754            assert_eq!(Int512::from(v).to_string(), v.to_string());
755        }
756
757        let result = Int512::try_from("34567");
758        assert_eq!(
759            result.unwrap().0,
760            I512::from_str_radix("34567", 10).unwrap()
761        );
762
763        let result = Int512::try_from("1.23");
764        assert!(result.is_err());
765    }
766
767    #[test]
768    fn int512_try_from_unsigned_works() {
769        test_try_from_uint_to_int::<Uint256, Int256>("Uint256", "Int256");
770        test_try_from_uint_to_int::<Uint512, Int256>("Uint512", "Int256");
771    }
772
773    #[test]
774    fn int512_implements_display() {
775        let a = Int512::from(12345u32);
776        assert_eq!(format!("Embedded: {a}"), "Embedded: 12345");
777        assert_eq!(a.to_string(), "12345");
778
779        let a = Int512::from(-12345i32);
780        assert_eq!(format!("Embedded: {a}"), "Embedded: -12345");
781        assert_eq!(a.to_string(), "-12345");
782
783        let a = Int512::zero();
784        assert_eq!(format!("Embedded: {a}"), "Embedded: 0");
785        assert_eq!(a.to_string(), "0");
786    }
787
788    #[test]
789    fn int512_display_padding_works() {
790        // width > natural representation
791        let a = Int512::from(123u64);
792        assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
793        let a = Int512::from(-123i64);
794        assert_eq!(format!("Embedded: {a:05}"), "Embedded: -0123");
795
796        // width < natural representation
797        let a = Int512::from(123u64);
798        assert_eq!(format!("Embedded: {a:02}"), "Embedded: 123");
799        let a = Int512::from(-123i64);
800        assert_eq!(format!("Embedded: {a:02}"), "Embedded: -123");
801    }
802
803    #[test]
804    fn int512_to_be_bytes_works() {
805        assert_eq!(Int512::zero().to_be_bytes(), [0; 64]);
806
807        let mut max = [0xff; 64];
808        max[0] = 0x7f;
809        assert_eq!(Int512::MAX.to_be_bytes(), max);
810
811        let mut one = [0; 64];
812        one[63] = 1;
813        assert_eq!(Int512::from(1u128).to_be_bytes(), one);
814        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "big")]`
815        assert_eq!(
816            Int512::from(240282366920938463463374607431768124608u128).to_be_bytes(),
817            [
818                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
819                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 196, 179, 87, 165,
820                121, 59, 133, 246, 117, 221, 191, 255, 254, 172, 192
821            ]
822        );
823        assert_eq!(
824            Int512::from_be_bytes([
825                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
826                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
827                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
828                252, 96, 230, 187, 38, 29
829            ])
830            .to_be_bytes(),
831            [
832                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
833                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
834                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
835                252, 96, 230, 187, 38, 29
836            ]
837        );
838    }
839
840    #[test]
841    fn int512_to_le_bytes_works() {
842        assert_eq!(Int512::zero().to_le_bytes(), [0; 64]);
843
844        let mut max = [0xff; 64];
845        max[63] = 0x7f;
846        assert_eq!(Int512::MAX.to_le_bytes(), max);
847
848        let mut one = [0; 64];
849        one[0] = 1;
850        assert_eq!(Int512::from(1u128).to_le_bytes(), one);
851        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "little")]`
852        assert_eq!(
853            Int512::from(240282366920938463463374607431768124608u128).to_le_bytes(),
854            [
855                192, 172, 254, 255, 191, 221, 117, 246, 133, 59, 121, 165, 87, 179, 196, 180, 0, 0,
856                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
857                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
858            ]
859        );
860        assert_eq!(
861            Int512::from_be_bytes([
862                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
863                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
864                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
865                252, 96, 230, 187, 38, 29
866            ])
867            .to_le_bytes(),
868            [
869                29, 38, 187, 230, 96, 252, 8, 99, 12, 47, 22, 13, 59, 44, 10, 64, 73, 154, 195,
870                166, 88, 14, 22, 85, 119, 238, 134, 208, 45, 106, 88, 218, 240, 150, 115, 200, 240,
871                2, 233, 42, 7, 192, 201, 211, 54, 65, 76, 87, 78, 67, 21, 33, 38, 0, 91, 58, 200,
872                123, 67, 87, 32, 23, 4, 17
873            ]
874        );
875    }
876
877    #[test]
878    fn int512_is_zero_works() {
879        assert!(Int512::zero().is_zero());
880        assert!(Int512(I512::from(0u32)).is_zero());
881
882        assert!(!Int512::from(1u32).is_zero());
883        assert!(!Int512::from(123u32).is_zero());
884        assert!(!Int512::from(-123i32).is_zero());
885    }
886
887    #[test]
888    fn int512_is_negative_works() {
889        assert!(Int512::MIN.is_negative());
890        assert!(Int512::from(-123i32).is_negative());
891
892        assert!(!Int512::MAX.is_negative());
893        assert!(!Int512::zero().is_negative());
894        assert!(!Int512::from(123u32).is_negative());
895    }
896
897    #[test]
898    fn int512_wrapping_methods() {
899        // wrapping_add
900        assert_eq!(
901            Int512::from(2u32).wrapping_add(Int512::from(2u32)),
902            Int512::from(4u32)
903        ); // non-wrapping
904        assert_eq!(Int512::MAX.wrapping_add(Int512::from(1u32)), Int512::MIN); // wrapping
905
906        // wrapping_sub
907        assert_eq!(
908            Int512::from(7u32).wrapping_sub(Int512::from(5u32)),
909            Int512::from(2u32)
910        ); // non-wrapping
911        assert_eq!(Int512::MIN.wrapping_sub(Int512::from(1u32)), Int512::MAX); // wrapping
912
913        // wrapping_mul
914        assert_eq!(
915            Int512::from(3u32).wrapping_mul(Int512::from(2u32)),
916            Int512::from(6u32)
917        ); // non-wrapping
918        assert_eq!(
919            Int512::MAX.wrapping_mul(Int512::from(2u32)),
920            Int512::from(-2i32)
921        ); // wrapping
922
923        // wrapping_pow
924        assert_eq!(Int512::from(2u32).wrapping_pow(3), Int512::from(8u32)); // non-wrapping
925        assert_eq!(Int512::MAX.wrapping_pow(2), Int512::from(1u32)); // wrapping
926    }
927
928    #[test]
929    fn int512_json() {
930        let orig = Int512::from(1234567890987654321u128);
931        let serialized = serde_json::to_vec(&orig).unwrap();
932        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
933        let parsed: Int512 = serde_json::from_slice(&serialized).unwrap();
934        assert_eq!(parsed, orig);
935    }
936
937    #[test]
938    fn int512_compare() {
939        let a = Int512::from(12345u32);
940        let b = Int512::from(23456u32);
941
942        assert!(a < b);
943        assert!(b > a);
944        assert_eq!(a, Int512::from(12345u32));
945    }
946
947    #[test]
948    #[allow(clippy::op_ref)]
949    fn int512_math() {
950        let a = Int512::from(-12345i32);
951        let b = Int512::from(23456u32);
952
953        // test + with owned and reference right hand side
954        assert_eq!(a + b, Int512::from(11111u32));
955        assert_eq!(a + &b, Int512::from(11111u32));
956
957        // test - with owned and reference right hand side
958        assert_eq!(b - a, Int512::from(35801u32));
959        assert_eq!(b - &a, Int512::from(35801u32));
960
961        // test += with owned and reference right hand side
962        let mut c = Int512::from(300000u32);
963        c += b;
964        assert_eq!(c, Int512::from(323456u32));
965        let mut d = Int512::from(300000u32);
966        d += &b;
967        assert_eq!(d, Int512::from(323456u32));
968
969        // test -= with owned and reference right hand side
970        let mut c = Int512::from(300000u32);
971        c -= b;
972        assert_eq!(c, Int512::from(276544u32));
973        let mut d = Int512::from(300000u32);
974        d -= &b;
975        assert_eq!(d, Int512::from(276544u32));
976
977        // test - with negative result
978        assert_eq!(a - b, Int512::from(-35801i32));
979    }
980
981    #[test]
982    #[should_panic]
983    fn int512_add_overflow_panics() {
984        let _ = Int512::MAX + Int512::from(12u32);
985    }
986
987    #[test]
988    #[allow(clippy::op_ref)]
989    fn int512_sub_works() {
990        assert_eq!(Int512::from(2u32) - Int512::from(1u32), Int512::from(1u32));
991        assert_eq!(Int512::from(2u32) - Int512::from(0u32), Int512::from(2u32));
992        assert_eq!(Int512::from(2u32) - Int512::from(2u32), Int512::from(0u32));
993        assert_eq!(Int512::from(2u32) - Int512::from(3u32), Int512::from(-1i32));
994
995        // works for refs
996        let a = Int512::from(10u32);
997        let b = Int512::from(3u32);
998        let expected = Int512::from(7u32);
999        assert_eq!(a - b, expected);
1000        assert_eq!(a - &b, expected);
1001        assert_eq!(&a - b, expected);
1002        assert_eq!(&a - &b, expected);
1003    }
1004
1005    #[test]
1006    #[should_panic]
1007    fn int512_sub_overflow_panics() {
1008        let _ = Int512::MIN + Int512::one() - Int512::from(2u32);
1009    }
1010
1011    #[test]
1012    fn int512_sub_assign_works() {
1013        let mut a = Int512::from(14u32);
1014        a -= Int512::from(2u32);
1015        assert_eq!(a, Int512::from(12u32));
1016
1017        // works for refs
1018        let mut a = Int512::from(10u32);
1019        let b = Int512::from(3u32);
1020        let expected = Int512::from(7u32);
1021        a -= &b;
1022        assert_eq!(a, expected);
1023    }
1024
1025    #[test]
1026    #[allow(clippy::op_ref)]
1027    fn int512_mul_works() {
1028        assert_eq!(Int512::from(2u32) * Int512::from(3u32), Int512::from(6u32));
1029        assert_eq!(Int512::from(2u32) * Int512::zero(), Int512::zero());
1030
1031        // works for refs
1032        let a = Int512::from(11u32);
1033        let b = Int512::from(3u32);
1034        let expected = Int512::from(33u32);
1035        assert_eq!(a * b, expected);
1036        assert_eq!(a * &b, expected);
1037        assert_eq!(&a * b, expected);
1038        assert_eq!(&a * &b, expected);
1039    }
1040
1041    #[test]
1042    fn int512_mul_assign_works() {
1043        let mut a = Int512::from(14u32);
1044        a *= Int512::from(2u32);
1045        assert_eq!(a, Int512::from(28u32));
1046
1047        // works for refs
1048        let mut a = Int512::from(10u32);
1049        let b = Int512::from(3u32);
1050        a *= &b;
1051        assert_eq!(a, Int512::from(30u32));
1052    }
1053
1054    #[test]
1055    fn int512_pow_works() {
1056        assert_eq!(Int512::from(2u32).pow(2), Int512::from(4u32));
1057        assert_eq!(Int512::from(2u32).pow(10), Int512::from(1024u32));
1058    }
1059
1060    #[test]
1061    #[should_panic]
1062    fn int512_pow_overflow_panics() {
1063        _ = Int512::MAX.pow(2u32);
1064    }
1065
1066    #[test]
1067    fn int512_shr_works() {
1068        let original = Int512::from_be_bytes([
1069            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1070            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1071            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1072            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8,
1073        ]);
1074
1075        let shifted = Int512::from_be_bytes([
1076            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1077            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1078            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1079            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8,
1080        ]);
1081
1082        assert_eq!(original >> 2u32, shifted);
1083    }
1084
1085    #[test]
1086    #[should_panic]
1087    fn int512_shr_overflow_panics() {
1088        let _ = Int512::from(1u32) >> 512u32;
1089    }
1090
1091    #[test]
1092    fn sum_works() {
1093        let nums = vec![
1094            Int512::from(17u32),
1095            Int512::from(123u32),
1096            Int512::from(540u32),
1097            Int512::from(82u32),
1098        ];
1099        let expected = Int512::from(762u32);
1100
1101        let sum_as_ref: Int512 = nums.iter().sum();
1102        assert_eq!(expected, sum_as_ref);
1103
1104        let sum_as_owned: Int512 = nums.into_iter().sum();
1105        assert_eq!(expected, sum_as_owned);
1106    }
1107
1108    #[test]
1109    fn int512_methods() {
1110        // checked_*
1111        assert!(matches!(
1112            Int512::MAX.checked_add(Int512::from(1u32)),
1113            Err(OverflowError { .. })
1114        ));
1115        assert_eq!(
1116            Int512::from(1u32).checked_add(Int512::from(1u32)),
1117            Ok(Int512::from(2u32)),
1118        );
1119        assert!(matches!(
1120            Int512::MIN.checked_sub(Int512::from(1u32)),
1121            Err(OverflowError { .. })
1122        ));
1123        assert_eq!(
1124            Int512::from(2u32).checked_sub(Int512::from(1u32)),
1125            Ok(Int512::from(1u32)),
1126        );
1127        assert!(matches!(
1128            Int512::MAX.checked_mul(Int512::from(2u32)),
1129            Err(OverflowError { .. })
1130        ));
1131        assert_eq!(
1132            Int512::from(2u32).checked_mul(Int512::from(2u32)),
1133            Ok(Int512::from(4u32)),
1134        );
1135        assert!(matches!(
1136            Int512::MAX.checked_pow(2u32),
1137            Err(OverflowError { .. })
1138        ));
1139        assert_eq!(Int512::from(2u32).checked_pow(3u32), Ok(Int512::from(8u32)),);
1140        assert_eq!(
1141            Int512::MAX.checked_div(Int512::from(0u32)),
1142            Err(DivisionError::DivideByZero)
1143        );
1144        assert_eq!(
1145            Int512::from(6u32).checked_div(Int512::from(2u32)),
1146            Ok(Int512::from(3u32)),
1147        );
1148        assert_eq!(
1149            Int512::MAX.checked_div_euclid(Int512::from(0u32)),
1150            Err(DivisionError::DivideByZero)
1151        );
1152        assert_eq!(
1153            Int512::from(6u32).checked_div_euclid(Int512::from(2u32)),
1154            Ok(Int512::from(3u32)),
1155        );
1156        assert_eq!(
1157            Int512::from(7u32).checked_div_euclid(Int512::from(2u32)),
1158            Ok(Int512::from(3u32)),
1159        );
1160        assert!(matches!(
1161            Int512::MAX.checked_rem(Int512::from(0u32)),
1162            Err(DivideByZeroError { .. })
1163        ));
1164        // checked_* with negative numbers
1165        assert_eq!(
1166            Int512::from(-12i32).checked_div(Int512::from(10i32)),
1167            Ok(Int512::from(-1i32)),
1168        );
1169        assert_eq!(
1170            Int512::from(-2i32).checked_pow(3u32),
1171            Ok(Int512::from(-8i32)),
1172        );
1173        assert_eq!(
1174            Int512::from(-6i32).checked_mul(Int512::from(-7i32)),
1175            Ok(Int512::from(42i32)),
1176        );
1177        assert_eq!(
1178            Int512::from(-2i32).checked_add(Int512::from(3i32)),
1179            Ok(Int512::from(1i32)),
1180        );
1181        assert_eq!(
1182            Int512::from(-1i32).checked_div_euclid(Int512::from(-2i32)),
1183            Ok(Int512::from(1u32)),
1184        );
1185
1186        // saturating_*
1187        assert_eq!(Int512::MAX.saturating_add(Int512::from(1u32)), Int512::MAX);
1188        assert_eq!(Int512::MIN.saturating_sub(Int512::from(1u32)), Int512::MIN);
1189        assert_eq!(Int512::MAX.saturating_mul(Int512::from(2u32)), Int512::MAX);
1190        assert_eq!(Int512::from(4u32).saturating_pow(2u32), Int512::from(16u32));
1191        assert_eq!(Int512::MAX.saturating_pow(2u32), Int512::MAX);
1192    }
1193
1194    #[test]
1195    #[allow(clippy::op_ref)]
1196    fn int512_implements_rem() {
1197        let a = Int512::from(10u32);
1198        assert_eq!(a % Int512::from(10u32), Int512::zero());
1199        assert_eq!(a % Int512::from(2u32), Int512::zero());
1200        assert_eq!(a % Int512::from(1u32), Int512::zero());
1201        assert_eq!(a % Int512::from(3u32), Int512::from(1u32));
1202        assert_eq!(a % Int512::from(4u32), Int512::from(2u32));
1203
1204        assert_eq!(
1205            Int512::from(-12i32) % Int512::from(10i32),
1206            Int512::from(-2i32)
1207        );
1208        assert_eq!(
1209            Int512::from(12i32) % Int512::from(-10i32),
1210            Int512::from(2i32)
1211        );
1212        assert_eq!(
1213            Int512::from(-12i32) % Int512::from(-10i32),
1214            Int512::from(-2i32)
1215        );
1216
1217        // works for refs
1218        let a = Int512::from(10u32);
1219        let b = Int512::from(3u32);
1220        let expected = Int512::from(1u32);
1221        assert_eq!(a % b, expected);
1222        assert_eq!(a % &b, expected);
1223        assert_eq!(&a % b, expected);
1224        assert_eq!(&a % &b, expected);
1225    }
1226
1227    #[test]
1228    #[should_panic(expected = "divisor of zero")]
1229    fn int512_rem_panics_for_zero() {
1230        let _ = Int512::from(10u32) % Int512::zero();
1231    }
1232
1233    #[test]
1234    fn int512_rem_assign_works() {
1235        let mut a = Int512::from(30u32);
1236        a %= Int512::from(4u32);
1237        assert_eq!(a, Int512::from(2u32));
1238
1239        // works for refs
1240        let mut a = Int512::from(25u32);
1241        let b = Int512::from(6u32);
1242        a %= &b;
1243        assert_eq!(a, Int512::from(1u32));
1244    }
1245
1246    #[test]
1247    fn int512_shr() {
1248        let x: Int512 = 0x8000_0000_0000_0000_0000_0000_0000_0000u128.into();
1249        assert_eq!(x >> 0, x); // right shift by 0 should be no-op
1250        assert_eq!(
1251            x >> 1,
1252            Int512::from(0x4000_0000_0000_0000_0000_0000_0000_0000u128)
1253        );
1254        assert_eq!(
1255            x >> 4,
1256            Int512::from(0x0800_0000_0000_0000_0000_0000_0000_0000u128)
1257        );
1258        // right shift of MIN value by the maximum shift value should result in -1 (filled with 1s)
1259        assert_eq!(
1260            Int512::MIN >> (core::mem::size_of::<Int512>() as u32 * 8 - 1),
1261            -Int512::one()
1262        );
1263    }
1264
1265    #[test]
1266    fn int512_shl() {
1267        let x: Int512 = 0x0800_0000_0000_0000_0000_0000_0000_0000u128.into();
1268        assert_eq!(x << 0, x); // left shift by 0 should be no-op
1269        assert_eq!(
1270            x << 1,
1271            Int512::from(0x1000_0000_0000_0000_0000_0000_0000_0000u128)
1272        );
1273        assert_eq!(
1274            x << 4,
1275            Int512::from(0x8000_0000_0000_0000_0000_0000_0000_0000u128)
1276        );
1277        // left shift by by the maximum shift value should result in MIN
1278        assert_eq!(
1279            Int512::one() << (core::mem::size_of::<Int512>() as u32 * 8 - 1),
1280            Int512::MIN
1281        );
1282    }
1283
1284    #[test]
1285    fn int512_abs_diff_works() {
1286        let a = Int512::from(42u32);
1287        let b = Int512::from(5u32);
1288        let expected = Uint512::from(37u32);
1289        assert_eq!(a.abs_diff(b), expected);
1290        assert_eq!(b.abs_diff(a), expected);
1291
1292        let c = Int512::from(-5i32);
1293        assert_eq!(b.abs_diff(c), Uint512::from(10u32));
1294        assert_eq!(c.abs_diff(b), Uint512::from(10u32));
1295    }
1296
1297    #[test]
1298    fn int512_abs_works() {
1299        let a = Int512::from(42i32);
1300        assert_eq!(a.abs(), a);
1301
1302        let b = Int512::from(-42i32);
1303        assert_eq!(b.abs(), a);
1304
1305        assert_eq!(Int512::zero().abs(), Int512::zero());
1306        assert_eq!((Int512::MIN + Int512::one()).abs(), Int512::MAX);
1307    }
1308
1309    #[test]
1310    fn int512_unsigned_abs_works() {
1311        assert_eq!(Int512::zero().unsigned_abs(), Uint512::zero());
1312        assert_eq!(Int512::one().unsigned_abs(), Uint512::one());
1313        assert_eq!(
1314            Int512::MIN.unsigned_abs(),
1315            Uint512::from_be_bytes(Int512::MAX.to_be_bytes()) + Uint512::one()
1316        );
1317
1318        let v = Int512::from(-42i32);
1319        assert_eq!(v.unsigned_abs(), v.abs_diff(Int512::zero()));
1320    }
1321
1322    #[test]
1323    #[should_panic = "attempt to calculate absolute value with overflow"]
1324    fn int512_abs_min_panics() {
1325        _ = Int512::MIN.abs();
1326    }
1327
1328    #[test]
1329    #[should_panic = "attempt to negate with overflow"]
1330    fn int512_neg_min_panics() {
1331        _ = -Int512::MIN;
1332    }
1333
1334    #[test]
1335    fn int512_partial_eq() {
1336        let test_cases = [(1, 1, true), (42, 42, true), (42, 24, false), (0, 0, true)]
1337            .into_iter()
1338            .map(|(lhs, rhs, expected): (u64, u64, bool)| {
1339                (Int512::from(lhs), Int512::from(rhs), expected)
1340            });
1341
1342        #[allow(clippy::op_ref)]
1343        for (lhs, rhs, expected) in test_cases {
1344            assert_eq!(lhs == rhs, expected);
1345            assert_eq!(&lhs == rhs, expected);
1346            assert_eq!(lhs == &rhs, expected);
1347            assert_eq!(&lhs == &rhs, expected);
1348        }
1349    }
1350}