rhdl_bits/
add.rs

1use std::ops::Add;
2use std::ops::AddAssign;
3
4use crate::bits::Bits;
5use crate::signed_bits::SignedBits;
6
7impl<const N: usize> Add<u128> for Bits<N> {
8    type Output = Self;
9    fn add(self, rhs: u128) -> Self::Output {
10        self + Bits::<N>::from(rhs)
11    }
12}
13
14impl<const N: usize> Add<Bits<N>> for u128 {
15    type Output = Bits<N>;
16    fn add(self, rhs: Bits<N>) -> Self::Output {
17        Bits::<N>::from(self) + rhs
18    }
19}
20
21impl<const N: usize> Add<Bits<N>> for Bits<N> {
22    type Output = Self;
23    #[allow(clippy::suspicious_arithmetic_impl)]
24    fn add(self, rhs: Self) -> Self::Output {
25        Self(u128::wrapping_add(self.0, rhs.0) & Self::mask().0)
26    }
27}
28
29impl<const N: usize> AddAssign<Bits<N>> for Bits<N> {
30    fn add_assign(&mut self, rhs: Bits<N>) {
31        *self = *self + rhs;
32    }
33}
34
35impl<const N: usize> AddAssign<u128> for Bits<N> {
36    fn add_assign(&mut self, rhs: u128) {
37        *self = *self + rhs;
38    }
39}
40
41impl<const N: usize> Add<i128> for SignedBits<N> {
42    type Output = Self;
43    fn add(self, rhs: i128) -> Self::Output {
44        self + SignedBits::<N>::from(rhs)
45    }
46}
47
48impl<const N: usize> Add<SignedBits<N>> for i128 {
49    type Output = SignedBits<N>;
50    fn add(self, rhs: SignedBits<N>) -> Self::Output {
51        SignedBits::<N>::from(self) + rhs
52    }
53}
54
55impl<const N: usize> Add<SignedBits<N>> for SignedBits<N> {
56    type Output = Self;
57    fn add(self, rhs: Self) -> Self::Output {
58        // Signed addition is the same as unsigned addition.
59        // But the result needs to be reinterpreted as a signed value.
60        (self.as_unsigned() + rhs.as_unsigned()).as_signed()
61    }
62}
63
64impl<const N: usize> AddAssign<i128> for SignedBits<N> {
65    fn add_assign(&mut self, rhs: i128) {
66        *self = *self + rhs;
67    }
68}
69
70impl<const N: usize> AddAssign<SignedBits<N>> for SignedBits<N> {
71    fn add_assign(&mut self, rhs: SignedBits<N>) {
72        *self = *self + rhs;
73    }
74}
75
76#[cfg(test)]
77mod test {
78    use super::*;
79
80    #[test]
81    fn test_add_bits() {
82        let bits: Bits<8> = 0b1101_1010.into();
83        let result = bits + bits;
84        assert_eq!(result.0, 180_u128);
85        let bits: Bits<8> = 0b1101_1010.into();
86        let result = bits + bits + bits;
87        assert_eq!(result.0, 142_u128);
88        let mut bits: Bits<128> = 0.into();
89        bits.set_bit(127, true);
90        let result = bits + bits;
91        assert_eq!(result.0, 0_u128);
92        let bits: Bits<54> = 0b1101_1010.into();
93        let result = bits + 1;
94        assert_eq!(result.0, 219_u128);
95        let result = 1 + bits;
96        assert_eq!(result.0, 219_u128);
97    }
98
99    #[test]
100    fn test_add_assign_bits() {
101        let mut bits: Bits<8> = 0b1101_1010.into();
102        bits += bits;
103        assert_eq!(bits.0, 180_u128);
104        let mut bits: Bits<8> = 0b1101_1010.into();
105        bits += bits;
106        bits += bits;
107        assert_eq!(bits.0, ((218 * 4) as u128) & 0xff);
108        let mut bits: Bits<128> = 0.into();
109        bits.set_bit(127, true);
110        bits += bits;
111        assert_eq!(bits.0, 0_u128);
112        let mut bits: Bits<54> = 0b1101_1010.into();
113        bits += 1;
114        assert_eq!(bits.0, 219_u128);
115    }
116
117    #[test]
118    fn test_signed_addition_matches_built_in_behavior_for_i8() {
119        for i in i8::MIN..i8::MAX {
120            for j in i8::MIN..i8::MAX {
121                let i_as_signed = SignedBits::<8>::from(i as i128);
122                let j_as_signed = SignedBits::<8>::from(j as i128);
123                let k_as_signed = i_as_signed + j_as_signed;
124                let k = i8::wrapping_add(i, j);
125                assert_eq!(k_as_signed.0, k as i128);
126            }
127        }
128    }
129
130    #[test]
131    fn test_signed_addition_matches_built_in_behavior_for_i64() {
132        for i in [i64::MIN, -1, 0, 1, i64::MAX] {
133            for j in [i64::MIN, -1, 0, 1, i64::MAX] {
134                let i_as_signed = SignedBits::<64>::from(i as i128);
135                let j_as_signed = SignedBits::<64>::from(j as i128);
136                let k_as_signed = i_as_signed + j_as_signed;
137                let k = i64::wrapping_add(i, j);
138                assert_eq!(k_as_signed.0, k as i128);
139            }
140        }
141    }
142
143    #[test]
144    fn test_signed_addition_matches_built_in_behavior_for_i128() {
145        for i in [i128::MIN, -1, 0, 1, i128::MAX] {
146            for j in [i128::MIN, -1, 0, 1, i128::MAX] {
147                let i_as_signed = SignedBits::<128>::from(i);
148                let j_as_signed = SignedBits::<128>::from(j);
149                let k_as_signed = i_as_signed + j_as_signed;
150                let k = i128::wrapping_add(i, j);
151                assert_eq!(k_as_signed.0, k);
152            }
153        }
154    }
155
156    #[test]
157    fn test_add_assign_signed() {
158        let mut x = SignedBits::<8>::from(1);
159        x += SignedBits::<8>::from(-2);
160        assert_eq!(x.0, -1);
161        x += 7;
162        assert_eq!(x.0, 6);
163    }
164}