cosmwasm_std/math/
int512.rs

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