1use super::{
2 const_ct_select, const_shl_ct, const_shl_impl, const_shr_ct, const_shr_impl, FixedUInt,
3 MachineWord,
4};
5
6use crate::const_numtraits::{
7 ConstCheckedShl, ConstCheckedShr, ConstOverflowingShl, ConstOverflowingShr,
8 ConstUnboundedShift, ConstWrappingShl, ConstWrappingShr, ConstZero,
9};
10use crate::machineword::ConstMachineWord;
11use crate::patch_num_traits::{OverflowingShl, OverflowingShr};
12use crate::personality::{Personality, PersonalityTag};
13
14c0nst::c0nst! {
15 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Not for FixedUInt<T, N, P> {
16 type Output = Self;
17 fn not(self) -> Self::Output {
18 let mut ret = <Self as ConstZero>::zero();
19 let mut i = 0;
20 while i < N {
21 ret.array[i] = !self.array[i];
22 i += 1;
23 }
24 ret
25 }
26 }
27
28 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitAnd<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
29 type Output = FixedUInt<T, N, P>;
30 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
31 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
32 let mut i = 0;
33 while i < N {
34 ret.array[i] = self.array[i] & other.array[i];
35 i += 1;
36 }
37 ret
38 }
39 }
40
41 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitAnd for FixedUInt<T, N, P> {
42 type Output = Self;
43 fn bitand(self, other: Self) -> Self::Output {
44 (&self).bitand(&other)
45 }
46 }
47
48 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitAnd<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
49 type Output = Self;
50 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
51 (&self).bitand(other)
52 }
53 }
54
55 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitAnd<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
56 type Output = FixedUInt<T, N, P>;
57 fn bitand(self, other: FixedUInt<T, N, P>) -> Self::Output {
58 self.bitand(&other)
59 }
60 }
61
62 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitAndAssign for FixedUInt<T, N, P> {
63 fn bitand_assign(&mut self, other: Self) {
64 let mut i = 0;
65 while i < N {
66 self.array[i] &= other.array[i];
67 i += 1;
68 }
69 }
70 }
71
72 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitOr<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
73 type Output = FixedUInt<T, N, P>;
74 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
75 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
76 let mut i = 0;
77 while i < N {
78 ret.array[i] = self.array[i] | other.array[i];
79 i += 1;
80 }
81 ret
82 }
83 }
84
85 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitOr for FixedUInt<T, N, P> {
86 type Output = Self;
87 fn bitor(self, other: Self) -> Self::Output {
88 (&self).bitor(&other)
89 }
90 }
91
92 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitOr<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
93 type Output = Self;
94 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
95 (&self).bitor(other)
96 }
97 }
98
99 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitOr<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
100 type Output = FixedUInt<T, N, P>;
101 fn bitor(self, other: FixedUInt<T, N, P>) -> Self::Output {
102 self.bitor(&other)
103 }
104 }
105
106 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitOrAssign for FixedUInt<T, N, P> {
107 fn bitor_assign(&mut self, other: Self) {
108 let mut i = 0;
109 while i < N {
110 self.array[i] |= other.array[i];
111 i += 1;
112 }
113 }
114 }
115
116 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitXor<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
117 type Output = FixedUInt<T, N, P>;
118 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
119 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
120 let mut i = 0;
121 while i < N {
122 ret.array[i] = self.array[i] ^ other.array[i];
123 i += 1;
124 }
125 ret
126 }
127 }
128
129 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitXor for FixedUInt<T, N, P> {
130 type Output = Self;
131 fn bitxor(self, other: Self) -> Self::Output {
132 (&self).bitxor(&other)
133 }
134 }
135
136 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitXor<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
137 type Output = Self;
138 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
139 (&self).bitxor(other)
140 }
141 }
142
143 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitXor<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
144 type Output = FixedUInt<T, N, P>;
145 fn bitxor(self, other: FixedUInt<T, N, P>) -> Self::Output {
146 self.bitxor(&other)
147 }
148 }
149
150 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::BitXorAssign for FixedUInt<T, N, P> {
151 fn bitxor_assign(&mut self, other: Self) {
152 let mut i = 0;
153 while i < N {
154 self.array[i] ^= other.array[i];
155 i += 1;
156 }
157 }
158 }
159
160 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<usize> for FixedUInt<T, N, P> {
162 type Output = Self;
163 fn shl(self, bits: usize) -> Self::Output {
164 let mut result = self;
165 match P::TAG {
166 PersonalityTag::Nct => const_shl_impl(&mut result, bits),
167 PersonalityTag::Ct => const_shl_ct(&mut result, bits),
168 }
169 result
170 }
171 }
172
173 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<usize> for FixedUInt<T, N, P> {
174 type Output = Self;
175 fn shr(self, bits: usize) -> Self::Output {
176 let mut result = self;
177 match P::TAG {
178 PersonalityTag::Nct => const_shr_impl(&mut result, bits),
179 PersonalityTag::Ct => const_shr_ct(&mut result, bits),
180 }
181 result
182 }
183 }
184
185 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<u32> for FixedUInt<T, N, P> {
186 type Output = Self;
187 fn shl(self, bits: u32) -> Self::Output {
188 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
192 if overflow { <Self as ConstZero>::zero() } else { self.shl(shift) }
193 }
194 }
195
196 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<u32> for FixedUInt<T, N, P> {
197 type Output = Self;
198 fn shr(self, bits: u32) -> Self::Output {
199 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
200 if overflow { <Self as ConstZero>::zero() } else { self.shr(shift) }
201 }
202 }
203
204 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<&usize> for FixedUInt<T, N, P> {
205 type Output = Self;
206 fn shl(self, bits: &usize) -> Self::Output {
207 self.shl(*bits)
208 }
209 }
210
211 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<&usize> for FixedUInt<T, N, P> {
212 type Output = Self;
213 fn shr(self, bits: &usize) -> Self::Output {
214 self.shr(*bits)
215 }
216 }
217
218 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<&u32> for FixedUInt<T, N, P> {
219 type Output = Self;
220 fn shl(self, bits: &u32) -> Self::Output {
221 self.shl(*bits)
222 }
223 }
224
225 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<&u32> for FixedUInt<T, N, P> {
226 type Output = Self;
227 fn shr(self, bits: &u32) -> Self::Output {
228 self.shr(*bits)
229 }
230 }
231
232 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<usize> for &FixedUInt<T, N, P> {
234 type Output = FixedUInt<T, N, P>;
235 fn shl(self, bits: usize) -> Self::Output {
236 (*self).shl(bits)
237 }
238 }
239
240 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<usize> for &FixedUInt<T, N, P> {
241 type Output = FixedUInt<T, N, P>;
242 fn shr(self, bits: usize) -> Self::Output {
243 (*self).shr(bits)
244 }
245 }
246
247 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<u32> for &FixedUInt<T, N, P> {
248 type Output = FixedUInt<T, N, P>;
249 fn shl(self, bits: u32) -> Self::Output {
250 (*self).shl(bits)
251 }
252 }
253
254 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<u32> for &FixedUInt<T, N, P> {
255 type Output = FixedUInt<T, N, P>;
256 fn shr(self, bits: u32) -> Self::Output {
257 (*self).shr(bits)
258 }
259 }
260
261 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<&usize> for &FixedUInt<T, N, P> {
262 type Output = FixedUInt<T, N, P>;
263 fn shl(self, bits: &usize) -> Self::Output {
264 (*self).shl(*bits)
265 }
266 }
267
268 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<&usize> for &FixedUInt<T, N, P> {
269 type Output = FixedUInt<T, N, P>;
270 fn shr(self, bits: &usize) -> Self::Output {
271 (*self).shr(*bits)
272 }
273 }
274
275 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shl<&u32> for &FixedUInt<T, N, P> {
276 type Output = FixedUInt<T, N, P>;
277 fn shl(self, bits: &u32) -> Self::Output {
278 (*self).shl(*bits)
279 }
280 }
281
282 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::Shr<&u32> for &FixedUInt<T, N, P> {
283 type Output = FixedUInt<T, N, P>;
284 fn shr(self, bits: &u32) -> Self::Output {
285 (*self).shr(*bits)
286 }
287 }
288
289 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::ShlAssign<usize> for FixedUInt<T, N, P> {
291 fn shl_assign(&mut self, bits: usize) {
292 match P::TAG {
293 PersonalityTag::Nct => const_shl_impl(self, bits),
294 PersonalityTag::Ct => const_shl_ct(self, bits),
295 }
296 }
297 }
298
299 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::ShrAssign<usize> for FixedUInt<T, N, P> {
300 fn shr_assign(&mut self, bits: usize) {
301 match P::TAG {
302 PersonalityTag::Nct => const_shr_impl(self, bits),
303 PersonalityTag::Ct => const_shr_ct(self, bits),
304 }
305 }
306 }
307
308 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::ShlAssign<&usize> for FixedUInt<T, N, P> {
309 fn shl_assign(&mut self, bits: &usize) {
310 match P::TAG {
311 PersonalityTag::Nct => const_shl_impl(self, *bits),
312 PersonalityTag::Ct => const_shl_ct(self, *bits),
313 }
314 }
315 }
316
317 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst core::ops::ShrAssign<&usize> for FixedUInt<T, N, P> {
318 fn shr_assign(&mut self, bits: &usize) {
319 match P::TAG {
320 PersonalityTag::Nct => const_shr_impl(self, *bits),
321 PersonalityTag::Ct => const_shr_ct(self, *bits),
322 }
323 }
324 }
325
326 c0nst fn normalize_shift_amount(bits: u32, bit_size: usize) -> (usize, bool) {
329 let bit_size_u32 = bit_size as u32;
330 if bit_size == 0 {
331 (0, true)
333 } else if bit_size_u32 == 0 {
334 (bits as usize, false)
337 } else if bits >= bit_size_u32 {
338 ((bits % bit_size_u32) as usize, true)
340 } else {
341 (bits as usize, false)
342 }
343 }
344
345 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstOverflowingShl for FixedUInt<T, N, P> {
346 fn overflowing_shl(&self, bits: u32) -> (Self, bool) {
347 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
348 let res = core::ops::Shl::<usize>::shl(*self, shift);
349 (res, overflow)
350 }
351 }
352
353 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstOverflowingShr for FixedUInt<T, N, P> {
354 fn overflowing_shr(&self, bits: u32) -> (Self, bool) {
355 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
356 let res = core::ops::Shr::<usize>::shr(*self, shift);
357 (res, overflow)
358 }
359 }
360
361 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstWrappingShl for FixedUInt<T, N, P> {
362 fn wrapping_shl(&self, bits: u32) -> Self {
363 ConstOverflowingShl::overflowing_shl(self, bits).0
364 }
365 }
366
367 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstWrappingShr for FixedUInt<T, N, P> {
368 fn wrapping_shr(&self, bits: u32) -> Self {
369 ConstOverflowingShr::overflowing_shr(self, bits).0
370 }
371 }
372
373 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstCheckedShl for FixedUInt<T, N, P> {
374 fn checked_shl(&self, bits: u32) -> Option<Self> {
375 let (res, overflow) = ConstOverflowingShl::overflowing_shl(self, bits);
376 if overflow { None } else { Some(res) }
377 }
378 }
379
380 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstCheckedShr for FixedUInt<T, N, P> {
381 fn checked_shr(&self, bits: u32) -> Option<Self> {
382 let (res, overflow) = ConstOverflowingShr::overflowing_shr(self, bits);
383 if overflow { None } else { Some(res) }
384 }
385 }
386
387 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstUnboundedShift for FixedUInt<T, N, P> {
388 fn unbounded_shl(self, rhs: u32) -> Self {
389 let (shift, overflow) = normalize_shift_amount(rhs, Self::BIT_SIZE);
390 match P::TAG {
391 PersonalityTag::Nct => {
392 if overflow {
393 Self::zero()
394 } else {
395 self << shift
396 }
397 }
398 PersonalityTag::Ct => {
399 let shifted = self << shift;
400 const_ct_select(shifted, Self::zero(), overflow as u8)
401 }
402 }
403 }
404
405 fn unbounded_shr(self, rhs: u32) -> Self {
406 let (shift, overflow) = normalize_shift_amount(rhs, Self::BIT_SIZE);
407 match P::TAG {
408 PersonalityTag::Nct => {
409 if overflow {
410 Self::zero()
411 } else {
412 self >> shift
413 }
414 }
415 PersonalityTag::Ct => {
416 let shifted = self >> shift;
417 const_ct_select(shifted, Self::zero(), overflow as u8)
418 }
419 }
420 }
421 }
422}
423
424impl<T: MachineWord, const N: usize, P: Personality> OverflowingShl for FixedUInt<T, N, P> {
426 fn overflowing_shl(self, bits: u32) -> (Self, bool) {
427 ConstOverflowingShl::overflowing_shl(&self, bits)
428 }
429}
430
431impl<T: MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
432 fn overflowing_shr(self, bits: u32) -> (Self, bool) {
433 ConstOverflowingShr::overflowing_shr(&self, bits)
434 }
435}
436
437impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
439 for FixedUInt<T, N, P>
440{
441 fn wrapping_shl(&self, bits: u32) -> Self {
442 ConstWrappingShl::wrapping_shl(self, bits)
443 }
444}
445
446impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
447 for FixedUInt<T, N, P>
448{
449 fn wrapping_shr(&self, bits: u32) -> Self {
450 ConstWrappingShr::wrapping_shr(self, bits)
451 }
452}
453
454impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
455 fn checked_shl(&self, bits: u32) -> Option<Self> {
456 ConstCheckedShl::checked_shl(self, bits)
457 }
458}
459
460impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
461 fn checked_shr(&self, bits: u32) -> Option<Self> {
462 ConstCheckedShr::checked_shr(self, bits)
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469
470 #[test]
471 fn test_bitand_combinations() {
472 let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a & b, expected);
478 assert_eq!(a & &b, expected);
480 assert_eq!(&a & b, expected);
482 assert_eq!(&a & &b, expected);
484 }
485
486 #[test]
487 fn test_bitor_combinations() {
488 let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(14u8); assert_eq!(a | b, expected);
494 assert_eq!(a | &b, expected);
496 assert_eq!(&a | b, expected);
498 assert_eq!(&a | &b, expected);
500 }
501
502 #[test]
503 fn test_bitxor_combinations() {
504 let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(6u8); assert_eq!(a ^ b, expected);
510 assert_eq!(a ^ &b, expected);
512 assert_eq!(&a ^ b, expected);
514 assert_eq!(&a ^ &b, expected);
516 }
517
518 #[test]
519 fn test_shl_combinations() {
520 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
522 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
526 assert_eq!(a << &shift, expected);
528 assert_eq!(&a << shift, expected);
530 assert_eq!(&a << &shift, expected);
532
533 let shift32: u32 = 2;
535 assert_eq!(a << shift32, expected);
536 assert_eq!(a << &shift32, expected);
537 assert_eq!(&a << shift32, expected);
538 assert_eq!(&a << &shift32, expected);
539 }
540
541 #[test]
542 fn test_shr_combinations() {
543 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
545 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
549 assert_eq!(a >> &shift, expected);
551 assert_eq!(&a >> shift, expected);
553 assert_eq!(&a >> &shift, expected);
555
556 let shift32: u32 = 2;
558 assert_eq!(a >> shift32, expected);
559 assert_eq!(a >> &shift32, expected);
560 assert_eq!(&a >> shift32, expected);
561 assert_eq!(&a >> &shift32, expected);
562 }
563
564 #[test]
565 fn test_const_bitops() {
566 type TestInt = FixedUInt<u8, 2>;
567
568 let a = TestInt::from(0b11001100u8);
569 let b = TestInt::from(0b10101010u8);
570
571 let not_a = !a;
573 assert_eq!(not_a.array[0], 0b00110011);
574 assert_eq!(not_a.array[1], 0xFF);
575
576 assert_eq!(a & b, TestInt::from(0b10001000u8));
578
579 assert_eq!(a | b, TestInt::from(0b11101110u8));
581
582 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
584
585 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
587
588 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
590
591 #[cfg(feature = "nightly")]
592 {
593 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
594 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
595
596 const NOT_A: TestInt = !A;
597 const AND_AB: TestInt = A & B;
598 const OR_AB: TestInt = A | B;
599 const XOR_AB: TestInt = A ^ B;
600 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
601 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
602
603 assert_eq!(NOT_A.array[0], 0b00110011);
604 assert_eq!(AND_AB.array[0], 0b10001000);
605 assert_eq!(OR_AB.array[0], 0b11101110);
606 assert_eq!(XOR_AB.array[0], 0b01100110);
607 assert_eq!(SHL_1.array[0], 16);
608 assert_eq!(SHR_16.array[0], 4);
609 }
610 }
611
612 #[test]
613 fn test_const_shift_traits() {
614 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 8);
619 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
621
622 let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 16);
623 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
625
626 let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 9);
627 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = ConstOverflowingShr::overflowing_shr(&b, 8);
633 assert_eq!(res.array, [1, 0]); assert!(!overflow);
635
636 let (res, overflow) = ConstOverflowingShr::overflowing_shr(&b, 16);
637 assert_eq!(res.array, [0, 1]); assert!(overflow);
639
640 let c = TestInt::from(1u8);
642 assert_eq!(ConstWrappingShl::wrapping_shl(&c, 4).array, [16, 0]);
643 assert_eq!(ConstWrappingShl::wrapping_shl(&c, 16).array, [1, 0]); assert_eq!(ConstWrappingShl::wrapping_shl(&c, 17).array, [2, 0]); let d = TestInt::from(0x8000u16);
648 assert_eq!(ConstWrappingShr::wrapping_shr(&d, 4).array, [0, 0x08]);
649 assert_eq!(ConstWrappingShr::wrapping_shr(&d, 16).array, [0, 0x80]); assert_eq!(ConstWrappingShr::wrapping_shr(&d, 17).array, [0, 0x40]); let e = TestInt::from(1u8);
654 assert_eq!(
655 ConstCheckedShl::checked_shl(&e, 4),
656 Some(TestInt::from(16u8))
657 );
658 assert_eq!(
659 ConstCheckedShl::checked_shl(&e, 15),
660 Some(TestInt::from(0x8000u16))
661 );
662 assert_eq!(ConstCheckedShl::checked_shl(&e, 16), None); let f = TestInt::from(0x8000u16);
666 assert_eq!(
667 ConstCheckedShr::checked_shr(&f, 15),
668 Some(TestInt::from(1u8))
669 );
670 assert_eq!(ConstCheckedShr::checked_shr(&f, 16), None); let g = TestInt::from(42u8);
674 assert_eq!(ConstOverflowingShl::overflowing_shl(&g, 0), (g, false));
675 assert_eq!(ConstOverflowingShr::overflowing_shr(&g, 0), (g, false));
676 assert_eq!(ConstWrappingShl::wrapping_shl(&g, 0), g);
677 assert_eq!(ConstWrappingShr::wrapping_shr(&g, 0), g);
678 assert_eq!(ConstCheckedShl::checked_shl(&g, 0), Some(g));
679 assert_eq!(ConstCheckedShr::checked_shr(&g, 0), Some(g));
680 }
681
682 #[test]
683 fn test_const_shift_traits_n0() {
684 type ZeroInt = FixedUInt<u8, 0>;
686 let z = ZeroInt::from_array([]);
687
688 assert_eq!(ConstOverflowingShl::overflowing_shl(&z, 0), (z, true));
690 assert_eq!(ConstOverflowingShr::overflowing_shr(&z, 0), (z, true));
691 assert_eq!(ConstWrappingShl::wrapping_shl(&z, 0), z);
692 assert_eq!(ConstWrappingShr::wrapping_shr(&z, 0), z);
693 assert_eq!(ConstCheckedShl::checked_shl(&z, 0), None);
694 assert_eq!(ConstCheckedShr::checked_shr(&z, 0), None);
695 }
696
697 #[test]
698 fn test_num_traits_shift_wrappers() {
699 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
700
701 type TestInt = FixedUInt<u8, 2>;
702
703 let a = TestInt::from(1u8);
704
705 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
707 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
711 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
712
713 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
715 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
716
717 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
719 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
720 }
721
722 #[test]
723 fn test_unbounded_shift() {
724 type U16 = FixedUInt<u8, 2>;
725
726 let one = U16::from(1u8);
727
728 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 0), one);
730 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 4), U16::from(16u8));
731 assert_eq!(
732 ConstUnboundedShift::unbounded_shl(one, 15),
733 U16::from(0x8000u16)
734 );
735
736 assert_eq!(
737 ConstUnboundedShift::unbounded_shr(U16::from(0x8000u16), 15),
738 one
739 );
740 assert_eq!(ConstUnboundedShift::unbounded_shr(U16::from(16u8), 4), one);
741
742 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 16), U16::from(0u8));
744 assert_eq!(
745 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 16),
746 U16::from(0u8)
747 );
748
749 assert_eq!(
751 ConstUnboundedShift::unbounded_shl(U16::from(0xFFFFu16), 17),
752 U16::from(0u8)
753 );
754 assert_eq!(
755 ConstUnboundedShift::unbounded_shl(U16::from(0xFFFFu16), 100),
756 U16::from(0u8)
757 );
758 assert_eq!(
759 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 17),
760 U16::from(0u8)
761 );
762 assert_eq!(
763 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 100),
764 U16::from(0u8)
765 );
766
767 type U32 = FixedUInt<u8, 4>;
769 let one32 = U32::from(1u8);
770 assert_eq!(
771 ConstUnboundedShift::unbounded_shl(one32, 31),
772 U32::from(0x80000000u32)
773 );
774 assert_eq!(
775 ConstUnboundedShift::unbounded_shl(one32, 32),
776 U32::from(0u8)
777 );
778 assert_eq!(
779 ConstUnboundedShift::unbounded_shr(U32::from(0x80000000u32), 31),
780 one32
781 );
782 assert_eq!(
783 ConstUnboundedShift::unbounded_shr(U32::from(0x80000000u32), 32),
784 U32::from(0u8)
785 );
786 }
787
788 #[test]
789 fn test_unbounded_shift_polymorphic() {
790 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
791 where
792 T: ConstUnboundedShift + Eq + core::fmt::Debug + Copy,
793 {
794 assert_eq!(ConstUnboundedShift::unbounded_shl(val, shift), expected_shl);
795 assert_eq!(ConstUnboundedShift::unbounded_shr(val, shift), expected_shr);
796 }
797
798 type U8x2 = FixedUInt<u8, 2>;
800 type U8x4 = FixedUInt<u8, 4>;
801 type U16x2 = FixedUInt<u16, 2>;
802
803 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
805 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
806 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
807
808 test_unbounded(1u8, 4, 16u8, 0u8);
810 test_unbounded(1u16, 4, 16u16, 0u16);
811 test_unbounded(1u32, 4, 16u32, 0u32);
812
813 test_unbounded(1u8, 8, 0u8, 0u8);
815 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
816 }
817}