concrete_commons/numeric/
unsigned.rs

1use std::ops::{
2    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
3    Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
4};
5
6use crate::numeric::CastInto;
7
8use super::{CastFrom, Numeric, SignedInteger};
9
10/// A trait shared by all the unsigned integer types.
11pub trait UnsignedInteger:
12    Numeric
13    + Ord
14    + Eq
15    + Add<Self, Output = Self>
16    + AddAssign<Self>
17    + Div<Self, Output = Self>
18    + DivAssign<Self>
19    + Mul<Self, Output = Self>
20    + MulAssign<Self>
21    + Rem<Self, Output = Self>
22    + RemAssign<Self>
23    + Sub<Self, Output = Self>
24    + SubAssign<Self>
25    + BitAnd<Self, Output = Self>
26    + BitAndAssign<Self>
27    + BitOr<Self, Output = Self>
28    + BitOrAssign<Self>
29    + BitXor<Self, Output = Self>
30    + BitXorAssign<Self>
31    + Not<Output = Self>
32    + Shl<usize, Output = Self>
33    + ShlAssign<usize>
34    + Shr<usize, Output = Self>
35    + ShrAssign<usize>
36    + CastFrom<f64>
37    + CastInto<f64>
38{
39    /// The signed type of the same precision.
40    type Signed: SignedInteger<Unsigned = Self> + CastFrom<Self>;
41    /// Compute an addition, modulo the max of the type.
42    #[must_use]
43    fn wrapping_add(self, other: Self) -> Self;
44    /// Compute a subtraction, modulo the max of the type.
45    #[must_use]
46    fn wrapping_sub(self, other: Self) -> Self;
47    /// Compute a division, modulo the max of the type.
48    #[must_use]
49    fn wrapping_div(self, other: Self) -> Self;
50    /// Compute a multiplication, modulo the max of the type.
51    #[must_use]
52    fn wrapping_mul(self, other: Self) -> Self;
53    /// Compute a negation, modulo the max of the type.
54    #[must_use]
55    fn wrapping_neg(self) -> Self;
56    /// Compute an exponentiation, modulo the max of the type.
57    #[must_use]
58    fn wrapping_pow(self, exp: u32) -> Self;
59    /// Panic free shift-left operation.
60    #[must_use]
61    fn wrapping_shl(self, rhs: u32) -> Self;
62    /// Panic free shift-right operation.
63    #[must_use]
64    fn wrapping_shr(self, rhs: u32) -> Self;
65    /// Returns the casting of the current value to the signed type of the same size.
66    fn into_signed(self) -> Self::Signed;
67    /// Returns a bit representation of the integer, where blocks of length `block_length` are
68    /// separated by whitespaces to increase the readability.
69    fn to_bits_string(&self, block_length: usize) -> String;
70}
71
72macro_rules! implement {
73    ($Type: tt, $SignedType:ty, $bits:expr) => {
74        impl Numeric for $Type {
75            const BITS: usize = $bits;
76            const ZERO: Self = 0;
77            const ONE: Self = 1;
78            const TWO: Self = 2;
79            const MAX: Self = <$Type>::MAX;
80        }
81        impl UnsignedInteger for $Type {
82            type Signed = $SignedType;
83            fn into_signed(self) -> Self::Signed {
84                Self::Signed::cast_from(self)
85            }
86            fn to_bits_string(&self, break_every: usize) -> String {
87                let mut strn = match <$Type as Numeric>::BITS {
88                    8 => format!("{:08b}", self),
89                    16 => format!("{:016b}", self),
90                    32 => format!("{:032b}", self),
91                    64 => format!("{:064b}", self),
92                    128 => format!("{:0128b}", self),
93                    _ => unreachable!(),
94                };
95                for i in (1..(<$Type as Numeric>::BITS / break_every)).rev() {
96                    strn.insert(i * break_every, ' ');
97                }
98                strn
99            }
100            fn wrapping_add(self, other: Self) -> Self {
101                self.wrapping_add(other)
102            }
103            fn wrapping_sub(self, other: Self) -> Self {
104                self.wrapping_sub(other)
105            }
106            fn wrapping_div(self, other: Self) -> Self {
107                self.wrapping_div(other)
108            }
109            fn wrapping_mul(self, other: Self) -> Self {
110                self.wrapping_mul(other)
111            }
112            fn wrapping_neg(self) -> Self {
113                self.wrapping_neg()
114            }
115            fn wrapping_shl(self, rhs: u32) -> Self {
116                self.wrapping_shl(rhs)
117            }
118            fn wrapping_shr(self, rhs: u32) -> Self {
119                self.wrapping_shr(rhs)
120            }
121            fn wrapping_pow(self, exp: u32) -> Self {
122                self.wrapping_pow(exp)
123            }
124        }
125    };
126}
127
128implement!(u8, i8, 8);
129implement!(u16, i16, 16);
130implement!(u32, i32, 32);
131implement!(u64, i64, 64);
132implement!(u128, i128, 128);
133
134#[cfg(test)]
135mod test {
136    use super::*;
137
138    #[test]
139    fn test_uint8_binary_rep() {
140        let a: u8 = 100;
141        let b = a.to_bits_string(4);
142        assert_eq!(b, "0110 0100".to_string());
143    }
144
145    #[test]
146    fn test_uint16_binary_rep() {
147        let a: u16 = 25702;
148        let b = a.to_bits_string(4);
149        assert_eq!(b, "0110 0100 0110 0110".to_string());
150    }
151
152    #[test]
153    fn test_uint32_binary_rep() {
154        let a: u32 = 1684411356;
155        let b = a.to_bits_string(4);
156        assert_eq!(b, "0110 0100 0110 0110 0001 0011 1101 1100".to_string());
157    }
158
159    #[test]
160    fn test_uint64_binary_rep() {
161        let a: u64 = 7_234_491_689_707_068_824;
162        let b = a.to_bits_string(4);
163        assert_eq!(
164            b,
165            "0110 0100 0110 0110 0001 0011 1101 1100 \
166                       1001 1111 1000 0001 0101 1101 1001 1000"
167                .to_string()
168        );
169    }
170
171    #[test]
172    fn test_uint128_binary_rep() {
173        let a: u128 = 124_282_366_920_938_463_463_374_121_543_098_288_434;
174        let b = a.to_bits_string(4);
175        assert_eq!(
176            b,
177            "0101 1101 0111 1111 1110 1001 1100 0111 \
178                       1000 1110 0110 0010 0000 0101 1011 0000 \
179                       1011 1000 0011 0000 0001 0000 1001 0110 \
180                       0011 1010 0110 1101 1100 1001 0011 0010"
181                .to_string()
182        );
183    }
184}