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