ruint/support/
num_traits.rs

1//! Support for the [`num-traits`](https://crates.io/crates/num-traits) crate.
2#![cfg(feature = "num-traits")]
3#![cfg_attr(docsrs, doc(cfg(feature = "num-traits")))]
4// This is a particularly big risk with these traits. Make sure
5// to call functions on the `Uint::` type.
6#![deny(unconditional_recursion)]
7use crate::Uint;
8use core::ops::{Shl, Shr};
9use num_traits::{
10    CheckedEuclid, Euclid, Inv, MulAdd, MulAddAssign, Num, NumCast,
11    bounds::Bounded,
12    cast::{FromPrimitive, ToPrimitive},
13    identities::{One, Zero},
14    int::PrimInt,
15    ops::{
16        bytes::{FromBytes, ToBytes},
17        checked::{
18            CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr,
19            CheckedSub,
20        },
21        overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub},
22        saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub},
23        wrapping::{WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub},
24    },
25    pow::Pow,
26    sign::Unsigned,
27};
28
29#[cfg(not(feature = "std"))]
30use alloc::vec::Vec;
31
32// TODO: AsPrimitive
33
34// Note. We can not implement `NumBytes` as it requires T to be `AsMut<[u8]>`.
35// This is not safe for `Uint` when `BITS % 8 != 0`.
36
37impl<const BITS: usize, const LIMBS: usize> Zero for Uint<BITS, LIMBS> {
38    #[inline(always)]
39    fn zero() -> Self {
40        Self::ZERO
41    }
42
43    #[inline(always)]
44    fn is_zero(&self) -> bool {
45        self.is_zero()
46    }
47}
48
49impl<const BITS: usize, const LIMBS: usize> One for Uint<BITS, LIMBS> {
50    #[inline(always)]
51    fn one() -> Self {
52        Self::ONE
53    }
54}
55
56impl<const BITS: usize, const LIMBS: usize> Bounded for Uint<BITS, LIMBS> {
57    #[inline(always)]
58    fn min_value() -> Self {
59        Self::ZERO
60    }
61
62    #[inline(always)]
63    fn max_value() -> Self {
64        Self::MAX
65    }
66}
67
68impl<const BITS: usize, const LIMBS: usize> FromBytes for Uint<BITS, LIMBS> {
69    type Bytes = [u8];
70
71    #[inline(always)]
72    fn from_le_bytes(bytes: &[u8]) -> Self {
73        Self::try_from_le_slice(bytes).unwrap()
74    }
75
76    #[inline(always)]
77    fn from_be_bytes(bytes: &[u8]) -> Self {
78        Self::try_from_be_slice(bytes).unwrap()
79    }
80}
81
82impl<const BITS: usize, const LIMBS: usize> ToBytes for Uint<BITS, LIMBS> {
83    type Bytes = Vec<u8>;
84
85    #[inline(always)]
86    fn to_le_bytes(&self) -> Self::Bytes {
87        self.to_le_bytes_vec()
88    }
89
90    #[inline(always)]
91    fn to_be_bytes(&self) -> Self::Bytes {
92        self.to_be_bytes_vec()
93    }
94}
95
96impl<const BITS: usize, const LIMBS: usize> CheckedAdd for Uint<BITS, LIMBS> {
97    #[inline(always)]
98    fn checked_add(&self, other: &Self) -> Option<Self> {
99        <Self>::checked_add(*self, *other)
100    }
101}
102
103impl<const BITS: usize, const LIMBS: usize> CheckedDiv for Uint<BITS, LIMBS> {
104    #[inline(always)]
105    fn checked_div(&self, other: &Self) -> Option<Self> {
106        <Self>::checked_div(*self, *other)
107    }
108}
109
110impl<const BITS: usize, const LIMBS: usize> CheckedMul for Uint<BITS, LIMBS> {
111    #[inline(always)]
112    fn checked_mul(&self, other: &Self) -> Option<Self> {
113        <Self>::checked_mul(*self, *other)
114    }
115}
116
117impl<const BITS: usize, const LIMBS: usize> CheckedNeg for Uint<BITS, LIMBS> {
118    #[inline(always)]
119    fn checked_neg(&self) -> Option<Self> {
120        <Self>::checked_neg(*self)
121    }
122}
123
124impl<const BITS: usize, const LIMBS: usize> CheckedRem for Uint<BITS, LIMBS> {
125    #[inline(always)]
126    fn checked_rem(&self, other: &Self) -> Option<Self> {
127        <Self>::checked_rem(*self, *other)
128    }
129}
130
131impl<const BITS: usize, const LIMBS: usize> CheckedShl for Uint<BITS, LIMBS> {
132    #[inline(always)]
133    fn checked_shl(&self, other: u32) -> Option<Self> {
134        <Self>::checked_shl(*self, other as usize)
135    }
136}
137
138impl<const BITS: usize, const LIMBS: usize> CheckedShr for Uint<BITS, LIMBS> {
139    #[inline(always)]
140    fn checked_shr(&self, other: u32) -> Option<Self> {
141        <Self>::checked_shr(*self, other as usize)
142    }
143}
144
145impl<const BITS: usize, const LIMBS: usize> CheckedSub for Uint<BITS, LIMBS> {
146    #[inline(always)]
147    fn checked_sub(&self, other: &Self) -> Option<Self> {
148        <Self>::checked_sub(*self, *other)
149    }
150}
151
152impl<const BITS: usize, const LIMBS: usize> CheckedEuclid for Uint<BITS, LIMBS> {
153    #[inline(always)]
154    fn checked_div_euclid(&self, v: &Self) -> Option<Self> {
155        <Self>::checked_div(*self, *v)
156    }
157
158    #[inline(always)]
159    fn checked_rem_euclid(&self, v: &Self) -> Option<Self> {
160        <Self>::checked_rem(*self, *v)
161    }
162}
163
164impl<const BITS: usize, const LIMBS: usize> Euclid for Uint<BITS, LIMBS> {
165    #[inline(always)]
166    fn div_euclid(&self, v: &Self) -> Self {
167        <Self>::wrapping_div(*self, *v)
168    }
169
170    #[inline(always)]
171    fn rem_euclid(&self, v: &Self) -> Self {
172        <Self>::wrapping_rem(*self, *v)
173    }
174}
175
176impl<const BITS: usize, const LIMBS: usize> Inv for Uint<BITS, LIMBS> {
177    type Output = Option<Self>;
178
179    #[inline(always)]
180    fn inv(self) -> Self::Output {
181        <Self>::inv_ring(self)
182    }
183}
184
185impl<const BITS: usize, const LIMBS: usize> MulAdd for Uint<BITS, LIMBS> {
186    type Output = Self;
187
188    #[inline(always)]
189    fn mul_add(self, a: Self, b: Self) -> Self::Output {
190        // OPT: Expose actual merged mul_add algo.
191        (self * a) + b
192    }
193}
194
195impl<const BITS: usize, const LIMBS: usize> MulAddAssign for Uint<BITS, LIMBS> {
196    #[inline(always)]
197    fn mul_add_assign(&mut self, a: Self, b: Self) {
198        *self *= a;
199        *self += b;
200    }
201}
202
203impl<const BITS: usize, const LIMBS: usize> Saturating for Uint<BITS, LIMBS> {
204    #[inline(always)]
205    fn saturating_add(self, v: Self) -> Self {
206        <Self>::saturating_add(self, v)
207    }
208
209    #[inline(always)]
210    fn saturating_sub(self, v: Self) -> Self {
211        <Self>::saturating_sub(self, v)
212    }
213}
214
215macro_rules! binary_op {
216    ($($trait:ident $fn:ident)*) => {$(
217        impl<const BITS: usize, const LIMBS: usize> $trait for Uint<BITS, LIMBS> {
218            #[inline(always)]
219            fn $fn(&self, v: &Self) -> Self {
220                <Self>::$fn(*self, *v)
221            }
222        }
223    )*};
224}
225
226binary_op! {
227    SaturatingAdd saturating_add
228    SaturatingSub saturating_sub
229    SaturatingMul saturating_mul
230    WrappingAdd wrapping_add
231    WrappingSub wrapping_sub
232    WrappingMul wrapping_mul
233}
234
235impl<const BITS: usize, const LIMBS: usize> WrappingNeg for Uint<BITS, LIMBS> {
236    #[inline(always)]
237    fn wrapping_neg(&self) -> Self {
238        <Self>::wrapping_neg(*self)
239    }
240}
241
242impl<const BITS: usize, const LIMBS: usize> WrappingShl for Uint<BITS, LIMBS> {
243    #[inline(always)]
244    fn wrapping_shl(&self, rhs: u32) -> Self {
245        <Self>::wrapping_shl(*self, rhs as usize)
246    }
247}
248
249impl<const BITS: usize, const LIMBS: usize> WrappingShr for Uint<BITS, LIMBS> {
250    #[inline(always)]
251    fn wrapping_shr(&self, rhs: u32) -> Self {
252        <Self>::wrapping_shr(*self, rhs as usize)
253    }
254}
255
256impl<const BITS: usize, const LIMBS: usize> OverflowingAdd for Uint<BITS, LIMBS> {
257    #[inline(always)]
258    fn overflowing_add(&self, v: &Self) -> (Self, bool) {
259        <Self>::overflowing_add(*self, *v)
260    }
261}
262
263impl<const BITS: usize, const LIMBS: usize> OverflowingSub for Uint<BITS, LIMBS> {
264    #[inline(always)]
265    fn overflowing_sub(&self, v: &Self) -> (Self, bool) {
266        <Self>::overflowing_sub(*self, *v)
267    }
268}
269
270impl<const BITS: usize, const LIMBS: usize> OverflowingMul for Uint<BITS, LIMBS> {
271    #[inline(always)]
272    fn overflowing_mul(&self, v: &Self) -> (Self, bool) {
273        <Self>::overflowing_mul(*self, *v)
274    }
275}
276
277impl<const BITS: usize, const LIMBS: usize> Num for Uint<BITS, LIMBS> {
278    type FromStrRadixErr = crate::ParseError;
279
280    #[inline(always)]
281    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
282        #[allow(clippy::cast_lossless)]
283        <Self>::from_str_radix(str, radix as u64)
284    }
285}
286
287impl<const BITS: usize, const LIMBS: usize> Pow<Self> for Uint<BITS, LIMBS> {
288    type Output = Self;
289
290    #[inline(always)]
291    fn pow(self, rhs: Self) -> Self::Output {
292        <Self>::pow(self, rhs)
293    }
294}
295
296impl<const BITS: usize, const LIMBS: usize> Unsigned for Uint<BITS, LIMBS> {}
297
298impl<const BITS: usize, const LIMBS: usize> ToPrimitive for Uint<BITS, LIMBS> {
299    #[inline(always)]
300    fn to_i64(&self) -> Option<i64> {
301        self.try_into().ok()
302    }
303
304    #[inline(always)]
305    fn to_u64(&self) -> Option<u64> {
306        self.try_into().ok()
307    }
308
309    #[inline(always)]
310    fn to_i128(&self) -> Option<i128> {
311        self.try_into().ok()
312    }
313
314    #[inline(always)]
315    fn to_u128(&self) -> Option<u128> {
316        self.try_into().ok()
317    }
318}
319
320impl<const BITS: usize, const LIMBS: usize> FromPrimitive for Uint<BITS, LIMBS> {
321    #[inline(always)]
322    fn from_i64(n: i64) -> Option<Self> {
323        Self::try_from(n).ok()
324    }
325
326    #[inline(always)]
327    fn from_u64(n: u64) -> Option<Self> {
328        Self::try_from(n).ok()
329    }
330
331    #[inline(always)]
332    fn from_i128(n: i128) -> Option<Self> {
333        Self::try_from(n).ok()
334    }
335
336    #[inline(always)]
337    fn from_u128(n: u128) -> Option<Self> {
338        Self::try_from(n).ok()
339    }
340}
341
342impl<const BITS: usize, const LIMBS: usize> NumCast for Uint<BITS, LIMBS> {
343    #[inline(always)]
344    fn from<T: ToPrimitive>(n: T) -> Option<Self> {
345        <Self>::try_from(n.to_u128()?).ok()
346    }
347}
348
349impl<const BITS: usize, const LIMBS: usize> PrimInt for Uint<BITS, LIMBS> {
350    #[inline(always)]
351    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
352    fn count_ones(self) -> u32 {
353        <Self>::count_ones(&self) as u32
354    }
355
356    #[inline(always)]
357    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
358    fn count_zeros(self) -> u32 {
359        <Self>::count_zeros(&self) as u32
360    }
361
362    #[inline(always)]
363    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
364    fn leading_zeros(self) -> u32 {
365        <Self>::leading_zeros(&self) as u32
366    }
367
368    #[inline(always)]
369    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
370    fn leading_ones(self) -> u32 {
371        <Self>::leading_ones(&self) as u32
372    }
373
374    #[inline(always)]
375    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
376    fn trailing_zeros(self) -> u32 {
377        <Self>::trailing_zeros(&self) as u32
378    }
379    #[inline(always)]
380    #[allow(clippy::cast_possible_truncation)] // Requires BITS > 2^32
381    fn trailing_ones(self) -> u32 {
382        <Self>::trailing_ones(&self) as u32
383    }
384
385    #[inline(always)]
386    fn rotate_left(self, n: u32) -> Self {
387        <Self>::rotate_left(self, n as usize)
388    }
389
390    #[inline(always)]
391    fn rotate_right(self, n: u32) -> Self {
392        <Self>::rotate_right(self, n as usize)
393    }
394
395    #[inline(always)]
396    fn signed_shl(self, n: u32) -> Self {
397        <Self>::shl(self, n as usize)
398    }
399
400    #[inline(always)]
401    fn signed_shr(self, n: u32) -> Self {
402        <Self>::arithmetic_shr(self, n as usize)
403    }
404
405    #[inline(always)]
406    fn unsigned_shl(self, n: u32) -> Self {
407        <Self>::shl(self, n as usize)
408    }
409
410    #[inline(always)]
411    fn unsigned_shr(self, n: u32) -> Self {
412        <Self>::shr(self, n as usize)
413    }
414
415    /// Note: This is not well-defined when `BITS % 8 != 0`.
416    fn swap_bytes(self) -> Self {
417        let mut bytes = self.to_be_bytes_vec();
418        bytes.reverse();
419        Self::try_from_be_slice(&bytes).unwrap()
420    }
421
422    #[inline(always)]
423    fn reverse_bits(self) -> Self {
424        <Self>::reverse_bits(self)
425    }
426
427    #[inline(always)]
428    fn from_be(x: Self) -> Self {
429        if cfg!(target_endian = "big") {
430            x
431        } else {
432            x.swap_bytes()
433        }
434    }
435
436    #[inline(always)]
437    fn from_le(x: Self) -> Self {
438        if cfg!(target_endian = "little") {
439            x
440        } else {
441            x.swap_bytes()
442        }
443    }
444
445    #[inline(always)]
446    fn to_be(self) -> Self {
447        if cfg!(target_endian = "big") {
448            self
449        } else {
450            self.swap_bytes()
451        }
452    }
453
454    #[inline(always)]
455    fn to_le(self) -> Self {
456        if cfg!(target_endian = "little") {
457            self
458        } else {
459            self.swap_bytes()
460        }
461    }
462
463    #[inline(always)]
464    fn pow(self, exp: u32) -> Self {
465        self.pow(Self::from(exp))
466    }
467}
468
469#[cfg(test)]
470mod tests {
471    use super::*;
472    use crate::aliases::{U64, U256};
473    use num_traits::bounds::{LowerBounded, UpperBounded};
474
475    macro_rules! assert_impl{
476        ($type:ident, $($trait:tt),*) => {
477            $({
478                fn assert_impl<T: $trait>() {}
479                assert_impl::<$type>();
480            })*
481        }
482    }
483
484    #[test]
485    fn test_assert_impl() {
486        // All applicable traits from num-traits (except AsPrimitive).
487        assert_impl!(U256, Bounded, LowerBounded, UpperBounded);
488        assert_impl!(U256, FromPrimitive, NumCast, ToPrimitive);
489        assert_impl!(U256, One, Zero);
490        assert_impl!(U256, PrimInt);
491        assert_impl!(U256, FromBytes, ToBytes);
492        assert_impl!(
493            U256, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub,
494            CheckedShl, CheckedShr, CheckedSub
495        );
496        assert_impl!(U256, CheckedEuclid, Euclid);
497        assert_impl!(U256, Inv);
498        assert_impl!(U256, MulAdd, MulAddAssign);
499        assert_impl!(U256, OverflowingAdd, OverflowingMul, OverflowingSub);
500        assert_impl!(
501            U256,
502            Saturating,
503            SaturatingAdd,
504            SaturatingMul,
505            SaturatingSub
506        );
507        assert_impl!(
508            U256,
509            WrappingAdd,
510            WrappingMul,
511            WrappingNeg,
512            WrappingShl,
513            WrappingShr,
514            WrappingSub
515        );
516        assert_impl!(U256, (Pow<U256>));
517        assert_impl!(U256, Unsigned);
518    }
519
520    #[test]
521    fn test_signed_shl() {
522        // Example from num-traits docs.
523        let n = U64::from(0x0123456789abcdefu64);
524        let m = U64::from(0x3456789abcdef000u64);
525        assert_eq!(n.signed_shl(12), m);
526    }
527
528    #[test]
529    fn test_signed_shr() {
530        // Example from num-traits docs.
531        let n = U64::from(0xfedcba9876543210u64);
532        let m = U64::from(0xffffedcba9876543u64);
533        assert_eq!(n.signed_shr(12), m);
534    }
535}