cosmwasm_std/math/
int512.rs

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