concrete_commons/numeric/
signed.rs

1use std::ops::{
2    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
3    Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
4};
5
6use crate::numeric::CastInto;
7
8use super::{CastFrom, Numeric, UnsignedInteger};
9
10/// A trait shared by all the unsigned integer types.
11pub trait SignedInteger:
12    Numeric
13    + Neg<Output = Self>
14    + Add<Self, Output = Self>
15    + AddAssign<Self>
16    + Div<Self, Output = Self>
17    + DivAssign<Self>
18    + Mul<Self, Output = Self>
19    + MulAssign<Self>
20    + Rem<Self, Output = Self>
21    + RemAssign<Self>
22    + Sub<Self, Output = Self>
23    + SubAssign<Self>
24    + BitAnd<Self, Output = Self>
25    + BitAndAssign<Self>
26    + BitOr<Self, Output = Self>
27    + BitOrAssign<Self>
28    + BitXor<Self, Output = Self>
29    + BitXorAssign<Self>
30    + Not<Output = Self>
31    + Shl<usize, Output = Self>
32    + ShlAssign<usize>
33    + Shr<usize, Output = Self>
34    + ShrAssign<usize>
35    + CastFrom<f64>
36    + CastInto<f64>
37{
38    /// The unsigned type of the same precicion
39    type Unsigned: UnsignedInteger<Signed = Self> + CastFrom<Self>;
40
41    /// Returns the casting of the current value to the unsigned type of the same size.
42    fn into_unsigned(self) -> Self::Unsigned;
43
44    /// Returns a bit representation of the integer, where blocks of length `block_length` are
45    /// separated by whitespaces to increase the readability.
46    fn to_bits_string(&self, block_length: usize) -> String;
47}
48
49macro_rules! implement {
50    ($Type: tt, $UnsignedType:ty, $bits:expr) => {
51        impl Numeric for $Type {
52            const BITS: usize = $bits;
53            const ZERO: Self = 0;
54            const ONE: Self = 1;
55            const TWO: Self = 2;
56            const MAX: Self = <$Type>::MAX;
57        }
58        impl SignedInteger for $Type {
59            type Unsigned = $UnsignedType;
60            fn into_unsigned(self) -> Self::Unsigned {
61                Self::Unsigned::cast_from(self)
62            }
63            fn to_bits_string(&self, break_every: usize) -> String {
64                let mut strn = match <$Type as Numeric>::BITS {
65                    8 => format!("{:08b}", self),
66                    16 => format!("{:016b}", self),
67                    32 => format!("{:032b}", self),
68                    64 => format!("{:064b}", self),
69                    128 => format!("{:0128b}", self),
70                    _ => unreachable!(),
71                };
72                for i in (1..(<$Type as Numeric>::BITS / break_every)).rev() {
73                    strn.insert(i * break_every, ' ');
74                }
75                strn
76            }
77        }
78    };
79}
80
81implement!(i8, u8, 8);
82implement!(i16, u16, 16);
83implement!(i32, u32, 32);
84implement!(i64, u64, 64);
85implement!(i128, u128, 128);
86
87#[cfg(test)]
88mod test {
89    use super::*;
90
91    #[test]
92    fn test_sint8_binary_rep() {
93        let a: i8 = -100;
94        let b = a.to_bits_string(4);
95        assert_eq!(b, "1001 1100".to_string());
96    }
97
98    #[test]
99    fn test_sint16_binary_rep() {
100        let a: i16 = -25702;
101        let b = a.to_bits_string(4);
102        assert_eq!(b, "1001 1011 1001 1010".to_string());
103    }
104
105    #[test]
106    fn test_sint32_binary_rep() {
107        let a: i32 = -1684411356;
108        let b = a.to_bits_string(4);
109        assert_eq!(b, "1001 1011 1001 1001 1110 1100 0010 0100".to_string());
110    }
111
112    #[test]
113    fn test_sint64_binary_rep() {
114        let a: i64 = -7_234_491_689_707_068_824;
115        let b = a.to_bits_string(4);
116        assert_eq!(
117            b,
118            "1001 1011 1001 1001 1110 1100 0010 0011 \
119                       0110 0000 0111 1110 1010 0010 0110 1000"
120                .to_string()
121        );
122    }
123
124    #[test]
125    fn test_sint128_binary_rep() {
126        let a: i128 = -124_282_366_920_938_463_463_374_121_543_098_288_434;
127        let b = a.to_bits_string(4);
128        assert_eq!(
129            b,
130            "1010 0010 1000 0000 0001 0110 0011 1000 \
131                       0111 0001 1001 1101 1111 1010 0100 1111 \
132                       0100 0111 1100 1111 1110 1111 0110 1001 \
133                       1100 0101 1001 0010 0011 0110 1100 1110"
134                .to_string()
135        );
136    }
137}