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