fixed_bigint/fixeduint/
bit_ops_impl.rs

1use super::{FixedUInt, MachineWord};
2
3use crate::patch_num_traits::{OverflowingShl, OverflowingShr};
4
5use num_traits::Zero;
6
7impl<T: MachineWord, const N: usize> core::ops::Not for FixedUInt<T, N> {
8    type Output = Self;
9    fn not(self) -> <Self as core::ops::Not>::Output {
10        let mut ret = Self::zero();
11        for i in 0..N {
12            ret.array[i] = !self.array[i]
13        }
14        ret
15    }
16}
17
18impl<T: MachineWord, const N: usize> core::ops::BitAnd<&FixedUInt<T, N>> for &FixedUInt<T, N> {
19    type Output = FixedUInt<T, N>;
20    fn bitand(self, other: &FixedUInt<T, N>) -> Self::Output {
21        let mut ret = Self::Output::zero();
22        for i in 0..N {
23            ret.array[i] = self.array[i] & other.array[i]
24        }
25        ret
26    }
27}
28
29impl<T: MachineWord, const N: usize> core::ops::BitAnd for FixedUInt<T, N> {
30    type Output = Self;
31    fn bitand(self, other: Self) -> Self::Output {
32        (&self).bitand(&other)
33    }
34}
35
36impl<T: MachineWord, const N: usize> core::ops::BitAnd<&FixedUInt<T, N>> for FixedUInt<T, N> {
37    type Output = Self;
38    fn bitand(self, other: &FixedUInt<T, N>) -> Self::Output {
39        (&self).bitand(other)
40    }
41}
42
43impl<T: MachineWord, const N: usize> core::ops::BitAnd<FixedUInt<T, N>> for &FixedUInt<T, N> {
44    type Output = FixedUInt<T, N>;
45    fn bitand(self, other: FixedUInt<T, N>) -> Self::Output {
46        self.bitand(&other)
47    }
48}
49
50impl<T: MachineWord, const N: usize> core::ops::BitAndAssign for FixedUInt<T, N> {
51    fn bitand_assign(&mut self, other: Self) {
52        for i in 0..N {
53            self.array[i] &= other.array[i]
54        }
55    }
56}
57
58impl<T: MachineWord, const N: usize> core::ops::BitOr<&FixedUInt<T, N>> for &FixedUInt<T, N> {
59    type Output = FixedUInt<T, N>;
60    fn bitor(self, other: &FixedUInt<T, N>) -> Self::Output {
61        let mut ret = Self::Output::zero();
62        for i in 0..N {
63            ret.array[i] = self.array[i] | other.array[i]
64        }
65        ret
66    }
67}
68
69impl<T: MachineWord, const N: usize> core::ops::BitOr for FixedUInt<T, N> {
70    type Output = Self;
71    fn bitor(self, other: Self) -> Self::Output {
72        (&self).bitor(&other)
73    }
74}
75
76impl<T: MachineWord, const N: usize> core::ops::BitOr<&FixedUInt<T, N>> for FixedUInt<T, N> {
77    type Output = Self;
78    fn bitor(self, other: &FixedUInt<T, N>) -> Self::Output {
79        (&self).bitor(other)
80    }
81}
82
83impl<T: MachineWord, const N: usize> core::ops::BitOr<FixedUInt<T, N>> for &FixedUInt<T, N> {
84    type Output = FixedUInt<T, N>;
85    fn bitor(self, other: FixedUInt<T, N>) -> Self::Output {
86        self.bitor(&other)
87    }
88}
89
90impl<T: MachineWord, const N: usize> core::ops::BitOrAssign for FixedUInt<T, N> {
91    fn bitor_assign(&mut self, other: Self) {
92        for i in 0..N {
93            self.array[i] |= other.array[i]
94        }
95    }
96}
97
98impl<T: MachineWord, const N: usize> core::ops::BitXor<&FixedUInt<T, N>> for &FixedUInt<T, N> {
99    type Output = FixedUInt<T, N>;
100    fn bitxor(self, other: &FixedUInt<T, N>) -> Self::Output {
101        let mut ret = Self::Output::zero();
102        for i in 0..N {
103            ret.array[i] = self.array[i] ^ other.array[i]
104        }
105        ret
106    }
107}
108
109impl<T: MachineWord, const N: usize> core::ops::BitXor for FixedUInt<T, N> {
110    type Output = Self;
111    fn bitxor(self, other: Self) -> Self::Output {
112        (&self).bitxor(&other)
113    }
114}
115
116impl<T: MachineWord, const N: usize> core::ops::BitXor<&FixedUInt<T, N>> for FixedUInt<T, N> {
117    type Output = Self;
118    fn bitxor(self, other: &FixedUInt<T, N>) -> Self::Output {
119        (&self).bitxor(other)
120    }
121}
122
123impl<T: MachineWord, const N: usize> core::ops::BitXor<FixedUInt<T, N>> for &FixedUInt<T, N> {
124    type Output = FixedUInt<T, N>;
125    fn bitxor(self, other: FixedUInt<T, N>) -> Self::Output {
126        self.bitxor(&other)
127    }
128}
129
130impl<T: MachineWord, const N: usize> core::ops::BitXorAssign for FixedUInt<T, N> {
131    fn bitxor_assign(&mut self, other: Self) {
132        for i in 0..N {
133            self.array[i] ^= other.array[i]
134        }
135    }
136}
137
138impl<T: MachineWord, const N: usize> OverflowingShl for FixedUInt<T, N> {
139    fn overflowing_shl(self, bits: u32) -> (Self, bool) {
140        let bitsu = bits as usize;
141        let (shift, overflow) = if bitsu >= Self::BIT_SIZE {
142            (bitsu & (Self::BIT_SIZE - 1), true)
143        } else {
144            (bitsu, false)
145        };
146        let res = core::ops::Shl::<usize>::shl(self, shift);
147        (res, overflow)
148    }
149}
150
151impl<T: MachineWord, const N: usize> core::ops::Shl<u32> for FixedUInt<T, N> {
152    type Output = Self;
153    fn shl(self, bits: u32) -> <Self as core::ops::Shl<u32>>::Output {
154        core::ops::Shl::<usize>::shl(self, bits as usize)
155    }
156}
157
158impl<T: MachineWord, const N: usize> core::ops::Shl<usize> for FixedUInt<T, N> {
159    type Output = Self;
160    fn shl(self, bits: usize) -> <Self as core::ops::Shl<usize>>::Output {
161        // This copy can be avoided
162        let mut result = self;
163        Self::shl_impl(&mut result, bits);
164        result
165    }
166}
167
168impl<T: MachineWord, const N: usize> core::ops::Shl<&'_ usize> for FixedUInt<T, N> {
169    type Output = Self;
170    fn shl(self, bits: &usize) -> <Self as core::ops::Shl<usize>>::Output {
171        let mut result = self;
172        Self::shl_impl(&mut result, *bits);
173        result
174    }
175}
176
177impl<T: MachineWord, const N: usize> num_traits::WrappingShl for FixedUInt<T, N> {
178    fn wrapping_shl(&self, bits: u32) -> Self {
179        self.overflowing_shl(bits).0
180    }
181}
182
183impl<T: MachineWord, const N: usize> num_traits::CheckedShl for FixedUInt<T, N> {
184    fn checked_shl(&self, bits: u32) -> Option<Self> {
185        let res = self.overflowing_shl(bits);
186        if res.1 {
187            None
188        } else {
189            Some(res.0)
190        }
191    }
192}
193
194// SaturatingShl doesn't exist
195
196impl<T: MachineWord, const N: usize> core::ops::ShlAssign<usize> for FixedUInt<T, N> {
197    fn shl_assign(&mut self, bits: usize) {
198        Self::shl_impl(self, bits);
199    }
200}
201
202impl<T: MachineWord, const N: usize> core::ops::ShlAssign<&'_ usize> for FixedUInt<T, N> {
203    fn shl_assign(&mut self, bits: &usize) {
204        Self::shl_impl(self, *bits);
205    }
206}
207
208impl<T: MachineWord, const N: usize> OverflowingShr for FixedUInt<T, N> {
209    fn overflowing_shr(self, bits: u32) -> (Self, bool) {
210        let bitsu = bits as usize;
211        let (shift, overflow) = if bitsu >= Self::BIT_SIZE {
212            (bitsu & (Self::BIT_SIZE - 1), true)
213        } else {
214            (bitsu, false)
215        };
216        let res = core::ops::Shr::<usize>::shr(self, shift);
217        (res, overflow)
218    }
219}
220
221impl<T: MachineWord, const N: usize> core::ops::Shr<u32> for FixedUInt<T, N> {
222    type Output = Self;
223    fn shr(self, bits: u32) -> <Self as core::ops::Shr<u32>>::Output {
224        core::ops::Shr::<usize>::shr(self, bits as usize)
225    }
226}
227
228impl<T: MachineWord, const N: usize> core::ops::Shr<usize> for FixedUInt<T, N> {
229    type Output = Self;
230    fn shr(self, bits: usize) -> <Self as core::ops::Shr<usize>>::Output {
231        // Technically, this copy can be avoided
232        let mut result = self;
233        Self::shr_impl(&mut result, bits);
234        result
235    }
236}
237
238impl<T: MachineWord, const N: usize> core::ops::Shr<&'_ usize> for FixedUInt<T, N> {
239    type Output = Self;
240    fn shr(self, bits: &usize) -> <Self as core::ops::Shr<usize>>::Output {
241        let mut result = self;
242        Self::shr_impl(&mut result, *bits);
243        result
244    }
245}
246
247impl<T: MachineWord, const N: usize> num_traits::WrappingShr for FixedUInt<T, N> {
248    fn wrapping_shr(&self, bits: u32) -> Self {
249        self.overflowing_shr(bits).0
250    }
251}
252
253impl<T: MachineWord, const N: usize> num_traits::CheckedShr for FixedUInt<T, N> {
254    fn checked_shr(&self, bits: u32) -> Option<Self> {
255        let res = self.overflowing_shr(bits);
256        if res.1 {
257            None
258        } else {
259            Some(res.0)
260        }
261    }
262}
263
264// SaturatingShr doesn't exist
265
266impl<T: MachineWord, const N: usize> core::ops::ShrAssign<usize> for FixedUInt<T, N> {
267    fn shr_assign(&mut self, bits: usize) {
268        Self::shr_impl(self, bits);
269    }
270}
271
272impl<T: MachineWord, const N: usize> core::ops::ShrAssign<&'_ usize> for FixedUInt<T, N> {
273    fn shr_assign(&mut self, bits: &usize) {
274        Self::shr_impl(self, *bits);
275    }
276}
277
278impl<T: MachineWord, const N: usize> core::ops::Shl<&usize> for &FixedUInt<T, N> {
279    type Output = FixedUInt<T, N>;
280    fn shl(self, bits: &usize) -> Self::Output {
281        let mut result = *self;
282        Self::Output::shl_impl(&mut result, *bits);
283        result
284    }
285}
286
287impl<T: MachineWord, const N: usize> core::ops::Shl<&u32> for &FixedUInt<T, N> {
288    type Output = FixedUInt<T, N>;
289    fn shl(self, bits: &u32) -> Self::Output {
290        self.shl(&(*bits as usize))
291    }
292}
293
294impl<T: MachineWord, const N: usize> core::ops::Shr<&usize> for &FixedUInt<T, N> {
295    type Output = FixedUInt<T, N>;
296    fn shr(self, bits: &usize) -> Self::Output {
297        let mut result = *self;
298        Self::Output::shr_impl(&mut result, *bits);
299        result
300    }
301}
302
303impl<T: MachineWord, const N: usize> core::ops::Shr<&u32> for &FixedUInt<T, N> {
304    type Output = FixedUInt<T, N>;
305    fn shr(self, bits: &u32) -> Self::Output {
306        self.shr(&(*bits as usize))
307    }
308}
309
310// Additional Shl implementations
311impl<T: MachineWord, const N: usize> core::ops::Shl<usize> for &FixedUInt<T, N> {
312    type Output = FixedUInt<T, N>;
313    fn shl(self, bits: usize) -> Self::Output {
314        self.shl(&bits)
315    }
316}
317
318impl<T: MachineWord, const N: usize> core::ops::Shl<u32> for &FixedUInt<T, N> {
319    type Output = FixedUInt<T, N>;
320    fn shl(self, bits: u32) -> Self::Output {
321        self.shl(&(bits as usize))
322    }
323}
324
325impl<T: MachineWord, const N: usize> core::ops::Shl<&u32> for FixedUInt<T, N> {
326    type Output = Self;
327    fn shl(self, bits: &u32) -> Self::Output {
328        self.shl(*bits)
329    }
330}
331
332// Additional Shr implementations
333impl<T: MachineWord, const N: usize> core::ops::Shr<usize> for &FixedUInt<T, N> {
334    type Output = FixedUInt<T, N>;
335    fn shr(self, bits: usize) -> Self::Output {
336        self.shr(&bits)
337    }
338}
339
340impl<T: MachineWord, const N: usize> core::ops::Shr<u32> for &FixedUInt<T, N> {
341    type Output = FixedUInt<T, N>;
342    fn shr(self, bits: u32) -> Self::Output {
343        self.shr(&(bits as usize))
344    }
345}
346
347impl<T: MachineWord, const N: usize> core::ops::Shr<&u32> for FixedUInt<T, N> {
348    type Output = Self;
349    fn shr(self, bits: &u32) -> Self::Output {
350        self.shr(*bits)
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use super::*;
357
358    #[test]
359    fn test_bitand_combinations() {
360        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
361        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
362        let expected = FixedUInt::<u8, 2>::from(8u8); // 1000
363
364        // value & value
365        assert_eq!(a & b, expected);
366        // value & ref
367        assert_eq!(a & &b, expected);
368        // ref & value
369        assert_eq!(&a & b, expected);
370        // ref & ref
371        assert_eq!(&a & &b, expected);
372    }
373
374    #[test]
375    fn test_bitor_combinations() {
376        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
377        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
378        let expected = FixedUInt::<u8, 2>::from(14u8); // 1110
379
380        // value | value
381        assert_eq!(a | b, expected);
382        // value | ref
383        assert_eq!(a | &b, expected);
384        // ref | value
385        assert_eq!(&a | b, expected);
386        // ref | ref
387        assert_eq!(&a | &b, expected);
388    }
389
390    #[test]
391    fn test_bitxor_combinations() {
392        let a = FixedUInt::<u8, 2>::from(12u8); // 1100
393        let b = FixedUInt::<u8, 2>::from(10u8); // 1010
394        let expected = FixedUInt::<u8, 2>::from(6u8); // 0110
395
396        // value ^ value
397        assert_eq!(a ^ b, expected);
398        // value ^ ref
399        assert_eq!(a ^ &b, expected);
400        // ref ^ value
401        assert_eq!(&a ^ b, expected);
402        // ref ^ ref
403        assert_eq!(&a ^ &b, expected);
404    }
405
406    #[test]
407    fn test_shl_combinations() {
408        let a = FixedUInt::<u8, 2>::from(2u8); // 0010
409        let shift: usize = 2;
410        let expected = FixedUInt::<u8, 2>::from(8u8); // 1000
411
412        // value << value
413        assert_eq!(a << shift, expected);
414        // value << ref
415        assert_eq!(a << &shift, expected);
416        // ref << value
417        assert_eq!(&a << shift, expected);
418        // ref << ref
419        assert_eq!(&a << &shift, expected);
420
421        // Same with u32
422        let shift32: u32 = 2;
423        assert_eq!(a << shift32, expected);
424        assert_eq!(a << &shift32, expected);
425        assert_eq!(&a << shift32, expected);
426        assert_eq!(&a << &shift32, expected);
427    }
428
429    #[test]
430    fn test_shr_combinations() {
431        let a = FixedUInt::<u8, 2>::from(8u8); // 1000
432        let shift: usize = 2;
433        let expected = FixedUInt::<u8, 2>::from(2u8); // 0010
434
435        // value >> value
436        assert_eq!(a >> shift, expected);
437        // value >> ref
438        assert_eq!(a >> &shift, expected);
439        // ref >> value
440        assert_eq!(&a >> shift, expected);
441        // ref >> ref
442        assert_eq!(&a >> &shift, expected);
443
444        // Same with u32
445        let shift32: u32 = 2;
446        assert_eq!(a >> shift32, expected);
447        assert_eq!(a >> &shift32, expected);
448        assert_eq!(&a >> shift32, expected);
449        assert_eq!(&a >> &shift32, expected);
450    }
451}