1use super::{const_shl_ct, const_shl_impl, const_shr_ct, const_shr_impl, FixedUInt, MachineWord};
2
3use crate::const_numtraits::{
4 ConstCheckedShl, ConstCheckedShr, ConstOverflowingShl, ConstOverflowingShr,
5 ConstUnboundedShift, ConstWrappingShl, ConstWrappingShr, ConstZero,
6};
7use crate::machineword::ConstMachineWord;
8use crate::patch_num_traits::{OverflowingShl, OverflowingShr};
9use crate::personality::{Personality, PersonalityTag};
10
11c0nst::c0nst! {
12 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Not for FixedUInt<T, N, P> {
13 type Output = Self;
14 fn not(self) -> Self::Output {
15 let mut ret = <Self as ConstZero>::zero();
16 let mut i = 0;
17 while i < N {
18 ret.array[i] = !self.array[i];
19 i += 1;
20 }
21 ret
22 }
23 }
24
25 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
26 type Output = FixedUInt<T, N, P>;
27 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
28 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
29 let mut i = 0;
30 while i < N {
31 ret.array[i] = self.array[i] & other.array[i];
32 i += 1;
33 }
34 ret
35 }
36 }
37
38 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd for FixedUInt<T, N, P> {
39 type Output = Self;
40 fn bitand(self, other: Self) -> Self::Output {
41 (&self).bitand(&other)
42 }
43 }
44
45 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
46 type Output = Self;
47 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
48 (&self).bitand(other)
49 }
50 }
51
52 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
53 type Output = FixedUInt<T, N, P>;
54 fn bitand(self, other: FixedUInt<T, N, P>) -> Self::Output {
55 self.bitand(&other)
56 }
57 }
58
59 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAndAssign for FixedUInt<T, N, P> {
60 fn bitand_assign(&mut self, other: Self) {
61 let mut i = 0;
62 while i < N {
63 self.array[i] &= other.array[i];
64 i += 1;
65 }
66 }
67 }
68
69 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
70 type Output = FixedUInt<T, N, P>;
71 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
72 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
73 let mut i = 0;
74 while i < N {
75 ret.array[i] = self.array[i] | other.array[i];
76 i += 1;
77 }
78 ret
79 }
80 }
81
82 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr for FixedUInt<T, N, P> {
83 type Output = Self;
84 fn bitor(self, other: Self) -> Self::Output {
85 (&self).bitor(&other)
86 }
87 }
88
89 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
90 type Output = Self;
91 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
92 (&self).bitor(other)
93 }
94 }
95
96 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
97 type Output = FixedUInt<T, N, P>;
98 fn bitor(self, other: FixedUInt<T, N, P>) -> Self::Output {
99 self.bitor(&other)
100 }
101 }
102
103 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOrAssign for FixedUInt<T, N, P> {
104 fn bitor_assign(&mut self, other: Self) {
105 let mut i = 0;
106 while i < N {
107 self.array[i] |= other.array[i];
108 i += 1;
109 }
110 }
111 }
112
113 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
114 type Output = FixedUInt<T, N, P>;
115 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
116 let mut ret = <FixedUInt<T, N, P> as ConstZero>::zero();
117 let mut i = 0;
118 while i < N {
119 ret.array[i] = self.array[i] ^ other.array[i];
120 i += 1;
121 }
122 ret
123 }
124 }
125
126 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor for FixedUInt<T, N, P> {
127 type Output = Self;
128 fn bitxor(self, other: Self) -> Self::Output {
129 (&self).bitxor(&other)
130 }
131 }
132
133 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
134 type Output = Self;
135 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
136 (&self).bitxor(other)
137 }
138 }
139
140 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
141 type Output = FixedUInt<T, N, P>;
142 fn bitxor(self, other: FixedUInt<T, N, P>) -> Self::Output {
143 self.bitxor(&other)
144 }
145 }
146
147 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXorAssign for FixedUInt<T, N, P> {
148 fn bitxor_assign(&mut self, other: Self) {
149 let mut i = 0;
150 while i < N {
151 self.array[i] ^= other.array[i];
152 i += 1;
153 }
154 }
155 }
156
157 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for FixedUInt<T, N, P> {
159 type Output = Self;
160 fn shl(self, bits: usize) -> Self::Output {
161 let mut result = self;
162 match P::TAG {
163 PersonalityTag::Nct => const_shl_impl(&mut result, bits),
164 PersonalityTag::Ct => const_shl_ct(&mut result, bits),
165 }
166 result
167 }
168 }
169
170 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for FixedUInt<T, N, P> {
171 type Output = Self;
172 fn shr(self, bits: usize) -> Self::Output {
173 let mut result = self;
174 match P::TAG {
175 PersonalityTag::Nct => const_shr_impl(&mut result, bits),
176 PersonalityTag::Ct => const_shr_ct(&mut result, bits),
177 }
178 result
179 }
180 }
181
182 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for FixedUInt<T, N, P> {
183 type Output = Self;
184 fn shl(self, bits: u32) -> Self::Output {
185 const_unbounded_shl_u32(self, bits)
186 }
187 }
188
189 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for FixedUInt<T, N, P> {
190 type Output = Self;
191 fn shr(self, bits: u32) -> Self::Output {
192 const_unbounded_shr_u32(self, bits)
193 }
194 }
195
196 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for FixedUInt<T, N, P> {
197 type Output = Self;
198 fn shl(self, bits: &usize) -> Self::Output {
199 self.shl(*bits)
200 }
201 }
202
203 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for FixedUInt<T, N, P> {
204 type Output = Self;
205 fn shr(self, bits: &usize) -> Self::Output {
206 self.shr(*bits)
207 }
208 }
209
210 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for FixedUInt<T, N, P> {
211 type Output = Self;
212 fn shl(self, bits: &u32) -> Self::Output {
213 self.shl(*bits)
214 }
215 }
216
217 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for FixedUInt<T, N, P> {
218 type Output = Self;
219 fn shr(self, bits: &u32) -> Self::Output {
220 self.shr(*bits)
221 }
222 }
223
224 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for &FixedUInt<T, N, P> {
226 type Output = FixedUInt<T, N, P>;
227 fn shl(self, bits: usize) -> Self::Output {
228 (*self).shl(bits)
229 }
230 }
231
232 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for &FixedUInt<T, N, P> {
233 type Output = FixedUInt<T, N, P>;
234 fn shr(self, bits: usize) -> Self::Output {
235 (*self).shr(bits)
236 }
237 }
238
239 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for &FixedUInt<T, N, P> {
240 type Output = FixedUInt<T, N, P>;
241 fn shl(self, bits: u32) -> Self::Output {
242 (*self).shl(bits)
243 }
244 }
245
246 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for &FixedUInt<T, N, P> {
247 type Output = FixedUInt<T, N, P>;
248 fn shr(self, bits: u32) -> Self::Output {
249 (*self).shr(bits)
250 }
251 }
252
253 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for &FixedUInt<T, N, P> {
254 type Output = FixedUInt<T, N, P>;
255 fn shl(self, bits: &usize) -> Self::Output {
256 (*self).shl(*bits)
257 }
258 }
259
260 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for &FixedUInt<T, N, P> {
261 type Output = FixedUInt<T, N, P>;
262 fn shr(self, bits: &usize) -> Self::Output {
263 (*self).shr(*bits)
264 }
265 }
266
267 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for &FixedUInt<T, N, P> {
268 type Output = FixedUInt<T, N, P>;
269 fn shl(self, bits: &u32) -> Self::Output {
270 (*self).shl(*bits)
271 }
272 }
273
274 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for &FixedUInt<T, N, P> {
275 type Output = FixedUInt<T, N, P>;
276 fn shr(self, bits: &u32) -> Self::Output {
277 (*self).shr(*bits)
278 }
279 }
280
281 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<usize> for FixedUInt<T, N, P> {
283 fn shl_assign(&mut self, bits: usize) {
284 match P::TAG {
285 PersonalityTag::Nct => const_shl_impl(self, bits),
286 PersonalityTag::Ct => const_shl_ct(self, bits),
287 }
288 }
289 }
290
291 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<usize> for FixedUInt<T, N, P> {
292 fn shr_assign(&mut self, bits: usize) {
293 match P::TAG {
294 PersonalityTag::Nct => const_shr_impl(self, bits),
295 PersonalityTag::Ct => const_shr_ct(self, bits),
296 }
297 }
298 }
299
300 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<&usize> for FixedUInt<T, N, P> {
301 fn shl_assign(&mut self, bits: &usize) {
302 match P::TAG {
303 PersonalityTag::Nct => const_shl_impl(self, *bits),
304 PersonalityTag::Ct => const_shl_ct(self, *bits),
305 }
306 }
307 }
308
309 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<&usize> for FixedUInt<T, N, P> {
310 fn shr_assign(&mut self, bits: &usize) {
311 match P::TAG {
312 PersonalityTag::Nct => const_shr_impl(self, *bits),
313 PersonalityTag::Ct => const_shr_ct(self, *bits),
314 }
315 }
316 }
317
318 pub(crate) c0nst fn const_unbounded_shl_u32<
325 T: [c0nst] ConstMachineWord + MachineWord,
326 const N: usize,
327 P: Personality,
328 >(
329 target: FixedUInt<T, N, P>,
330 bits: u32,
331 ) -> FixedUInt<T, N, P> {
332 match P::TAG {
333 PersonalityTag::Nct => {
334 let (shift, overflow) =
335 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
336 if overflow {
337 <FixedUInt<T, N, P> as ConstZero>::zero()
338 } else {
339 target << shift
340 }
341 }
342 PersonalityTag::Ct => {
343 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
357 let capped = const_ct_min_u32(bits, bit_size_u32);
358 target << (capped as usize)
359 }
360 }
361 }
362
363 pub(crate) c0nst fn const_unbounded_shr_u32<
365 T: [c0nst] ConstMachineWord + MachineWord,
366 const N: usize,
367 P: Personality,
368 >(
369 target: FixedUInt<T, N, P>,
370 bits: u32,
371 ) -> FixedUInt<T, N, P> {
372 match P::TAG {
373 PersonalityTag::Nct => {
374 let (shift, overflow) =
375 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
376 if overflow {
377 <FixedUInt<T, N, P> as ConstZero>::zero()
378 } else {
379 target >> shift
380 }
381 }
382 PersonalityTag::Ct => {
383 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
386 let capped = const_ct_min_u32(bits, bit_size_u32);
387 target >> (capped as usize)
388 }
389 }
390 }
391
392 c0nst fn const_ct_min_u32(bits: u32, cap: u32) -> u32 {
399 let diff = cap.wrapping_sub(bits);
401 let too_big_bit = (diff >> 31) & 1;
402 let too_big_mask = core::hint::black_box(too_big_bit.wrapping_neg());
403 bits ^ (too_big_mask & (bits ^ cap))
406 }
407
408 c0nst fn normalize_shift_amount(bits: u32, bit_size: usize) -> (usize, bool) {
411 let bit_size_u32 = bit_size as u32;
412 if bit_size == 0 {
413 (0, true)
415 } else if bit_size_u32 == 0 {
416 (bits as usize, false)
419 } else if bits >= bit_size_u32 {
420 ((bits % bit_size_u32) as usize, true)
422 } else {
423 (bits as usize, false)
424 }
425 }
426
427 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstOverflowingShl for FixedUInt<T, N, P> {
428 fn overflowing_shl(&self, bits: u32) -> (Self, bool) {
429 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
430 let res = core::ops::Shl::<usize>::shl(*self, shift);
431 (res, overflow)
432 }
433 }
434
435 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstOverflowingShr for FixedUInt<T, N, P> {
436 fn overflowing_shr(&self, bits: u32) -> (Self, bool) {
437 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
438 let res = core::ops::Shr::<usize>::shr(*self, shift);
439 (res, overflow)
440 }
441 }
442
443 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstWrappingShl for FixedUInt<T, N, P> {
444 fn wrapping_shl(&self, bits: u32) -> Self {
445 ConstOverflowingShl::overflowing_shl(self, bits).0
446 }
447 }
448
449 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstWrappingShr for FixedUInt<T, N, P> {
450 fn wrapping_shr(&self, bits: u32) -> Self {
451 ConstOverflowingShr::overflowing_shr(self, bits).0
452 }
453 }
454
455 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstCheckedShl for FixedUInt<T, N, P> {
456 fn checked_shl(&self, bits: u32) -> Option<Self> {
457 let (res, overflow) = ConstOverflowingShl::overflowing_shl(self, bits);
458 if overflow { None } else { Some(res) }
459 }
460 }
461
462 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstCheckedShr for FixedUInt<T, N, P> {
463 fn checked_shr(&self, bits: u32) -> Option<Self> {
464 let (res, overflow) = ConstOverflowingShr::overflowing_shr(self, bits);
465 if overflow { None } else { Some(res) }
466 }
467 }
468
469 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> ConstUnboundedShift for FixedUInt<T, N, P> {
470 fn unbounded_shl(self, rhs: u32) -> Self {
471 const_unbounded_shl_u32(self, rhs)
472 }
473
474 fn unbounded_shr(self, rhs: u32) -> Self {
475 const_unbounded_shr_u32(self, rhs)
476 }
477 }
478}
479
480impl<T: MachineWord, const N: usize, P: Personality> OverflowingShl for FixedUInt<T, N, P> {
482 fn overflowing_shl(self, bits: u32) -> (Self, bool) {
483 ConstOverflowingShl::overflowing_shl(&self, bits)
484 }
485}
486
487impl<T: MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
488 fn overflowing_shr(self, bits: u32) -> (Self, bool) {
489 ConstOverflowingShr::overflowing_shr(&self, bits)
490 }
491}
492
493impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
495 for FixedUInt<T, N, P>
496{
497 fn wrapping_shl(&self, bits: u32) -> Self {
498 ConstWrappingShl::wrapping_shl(self, bits)
499 }
500}
501
502impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
503 for FixedUInt<T, N, P>
504{
505 fn wrapping_shr(&self, bits: u32) -> Self {
506 ConstWrappingShr::wrapping_shr(self, bits)
507 }
508}
509
510impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
511 fn checked_shl(&self, bits: u32) -> Option<Self> {
512 ConstCheckedShl::checked_shl(self, bits)
513 }
514}
515
516impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
517 fn checked_shr(&self, bits: u32) -> Option<Self> {
518 ConstCheckedShr::checked_shr(self, bits)
519 }
520}
521
522#[cfg(test)]
523mod tests {
524 use super::*;
525
526 #[test]
527 fn test_bitand_combinations() {
528 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);
534 assert_eq!(a & &b, expected);
536 assert_eq!(&a & b, expected);
538 assert_eq!(&a & &b, expected);
540 }
541
542 #[test]
543 fn test_bitor_combinations() {
544 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);
550 assert_eq!(a | &b, expected);
552 assert_eq!(&a | b, expected);
554 assert_eq!(&a | &b, expected);
556 }
557
558 #[test]
559 fn test_bitxor_combinations() {
560 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);
566 assert_eq!(a ^ &b, expected);
568 assert_eq!(&a ^ b, expected);
570 assert_eq!(&a ^ &b, expected);
572 }
573
574 #[test]
575 fn test_shl_combinations() {
576 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
578 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
582 assert_eq!(a << &shift, expected);
584 assert_eq!(&a << shift, expected);
586 assert_eq!(&a << &shift, expected);
588
589 let shift32: u32 = 2;
591 assert_eq!(a << shift32, expected);
592 assert_eq!(a << &shift32, expected);
593 assert_eq!(&a << shift32, expected);
594 assert_eq!(&a << &shift32, expected);
595 }
596
597 #[test]
598 fn test_shr_combinations() {
599 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
601 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
605 assert_eq!(a >> &shift, expected);
607 assert_eq!(&a >> shift, expected);
609 assert_eq!(&a >> &shift, expected);
611
612 let shift32: u32 = 2;
614 assert_eq!(a >> shift32, expected);
615 assert_eq!(a >> &shift32, expected);
616 assert_eq!(&a >> shift32, expected);
617 assert_eq!(&a >> &shift32, expected);
618 }
619
620 #[test]
621 fn test_const_bitops() {
622 type TestInt = FixedUInt<u8, 2>;
623
624 let a = TestInt::from(0b11001100u8);
625 let b = TestInt::from(0b10101010u8);
626
627 let not_a = !a;
629 assert_eq!(not_a.array[0], 0b00110011);
630 assert_eq!(not_a.array[1], 0xFF);
631
632 assert_eq!(a & b, TestInt::from(0b10001000u8));
634
635 assert_eq!(a | b, TestInt::from(0b11101110u8));
637
638 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
640
641 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
643
644 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
646
647 #[cfg(feature = "nightly")]
648 {
649 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
650 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
651
652 const NOT_A: TestInt = !A;
653 const AND_AB: TestInt = A & B;
654 const OR_AB: TestInt = A | B;
655 const XOR_AB: TestInt = A ^ B;
656 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
657 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
658
659 assert_eq!(NOT_A.array[0], 0b00110011);
660 assert_eq!(AND_AB.array[0], 0b10001000);
661 assert_eq!(OR_AB.array[0], 0b11101110);
662 assert_eq!(XOR_AB.array[0], 0b01100110);
663 assert_eq!(SHL_1.array[0], 16);
664 assert_eq!(SHR_16.array[0], 4);
665 }
666 }
667
668 #[test]
669 fn test_const_shift_traits() {
670 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 8);
675 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
677
678 let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 16);
679 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
681
682 let (res, overflow) = ConstOverflowingShl::overflowing_shl(&a, 9);
683 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = ConstOverflowingShr::overflowing_shr(&b, 8);
689 assert_eq!(res.array, [1, 0]); assert!(!overflow);
691
692 let (res, overflow) = ConstOverflowingShr::overflowing_shr(&b, 16);
693 assert_eq!(res.array, [0, 1]); assert!(overflow);
695
696 let c = TestInt::from(1u8);
698 assert_eq!(ConstWrappingShl::wrapping_shl(&c, 4).array, [16, 0]);
699 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);
704 assert_eq!(ConstWrappingShr::wrapping_shr(&d, 4).array, [0, 0x08]);
705 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);
710 assert_eq!(
711 ConstCheckedShl::checked_shl(&e, 4),
712 Some(TestInt::from(16u8))
713 );
714 assert_eq!(
715 ConstCheckedShl::checked_shl(&e, 15),
716 Some(TestInt::from(0x8000u16))
717 );
718 assert_eq!(ConstCheckedShl::checked_shl(&e, 16), None); let f = TestInt::from(0x8000u16);
722 assert_eq!(
723 ConstCheckedShr::checked_shr(&f, 15),
724 Some(TestInt::from(1u8))
725 );
726 assert_eq!(ConstCheckedShr::checked_shr(&f, 16), None); let g = TestInt::from(42u8);
730 assert_eq!(ConstOverflowingShl::overflowing_shl(&g, 0), (g, false));
731 assert_eq!(ConstOverflowingShr::overflowing_shr(&g, 0), (g, false));
732 assert_eq!(ConstWrappingShl::wrapping_shl(&g, 0), g);
733 assert_eq!(ConstWrappingShr::wrapping_shr(&g, 0), g);
734 assert_eq!(ConstCheckedShl::checked_shl(&g, 0), Some(g));
735 assert_eq!(ConstCheckedShr::checked_shr(&g, 0), Some(g));
736 }
737
738 #[test]
739 fn test_const_shift_traits_n0() {
740 type ZeroInt = FixedUInt<u8, 0>;
742 let z = ZeroInt::from_array([]);
743
744 assert_eq!(ConstOverflowingShl::overflowing_shl(&z, 0), (z, true));
746 assert_eq!(ConstOverflowingShr::overflowing_shr(&z, 0), (z, true));
747 assert_eq!(ConstWrappingShl::wrapping_shl(&z, 0), z);
748 assert_eq!(ConstWrappingShr::wrapping_shr(&z, 0), z);
749 assert_eq!(ConstCheckedShl::checked_shl(&z, 0), None);
750 assert_eq!(ConstCheckedShr::checked_shr(&z, 0), None);
751 }
752
753 #[test]
754 fn test_num_traits_shift_wrappers() {
755 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
756
757 type TestInt = FixedUInt<u8, 2>;
758
759 let a = TestInt::from(1u8);
760
761 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
763 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
767 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
768
769 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
771 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
772
773 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
775 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
776 }
777
778 #[test]
779 fn test_unbounded_shift() {
780 type U16 = FixedUInt<u8, 2>;
781
782 let one = U16::from(1u8);
783
784 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 0), one);
786 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 4), U16::from(16u8));
787 assert_eq!(
788 ConstUnboundedShift::unbounded_shl(one, 15),
789 U16::from(0x8000u16)
790 );
791
792 assert_eq!(
793 ConstUnboundedShift::unbounded_shr(U16::from(0x8000u16), 15),
794 one
795 );
796 assert_eq!(ConstUnboundedShift::unbounded_shr(U16::from(16u8), 4), one);
797
798 assert_eq!(ConstUnboundedShift::unbounded_shl(one, 16), U16::from(0u8));
800 assert_eq!(
801 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 16),
802 U16::from(0u8)
803 );
804
805 assert_eq!(
807 ConstUnboundedShift::unbounded_shl(U16::from(0xFFFFu16), 17),
808 U16::from(0u8)
809 );
810 assert_eq!(
811 ConstUnboundedShift::unbounded_shl(U16::from(0xFFFFu16), 100),
812 U16::from(0u8)
813 );
814 assert_eq!(
815 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 17),
816 U16::from(0u8)
817 );
818 assert_eq!(
819 ConstUnboundedShift::unbounded_shr(U16::from(0xFFFFu16), 100),
820 U16::from(0u8)
821 );
822
823 type U32 = FixedUInt<u8, 4>;
825 let one32 = U32::from(1u8);
826 assert_eq!(
827 ConstUnboundedShift::unbounded_shl(one32, 31),
828 U32::from(0x80000000u32)
829 );
830 assert_eq!(
831 ConstUnboundedShift::unbounded_shl(one32, 32),
832 U32::from(0u8)
833 );
834 assert_eq!(
835 ConstUnboundedShift::unbounded_shr(U32::from(0x80000000u32), 31),
836 one32
837 );
838 assert_eq!(
839 ConstUnboundedShift::unbounded_shr(U32::from(0x80000000u32), 32),
840 U32::from(0u8)
841 );
842 }
843
844 #[test]
845 fn test_unbounded_shift_polymorphic() {
846 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
847 where
848 T: ConstUnboundedShift + Eq + core::fmt::Debug + Copy,
849 {
850 assert_eq!(ConstUnboundedShift::unbounded_shl(val, shift), expected_shl);
851 assert_eq!(ConstUnboundedShift::unbounded_shr(val, shift), expected_shr);
852 }
853
854 type U8x2 = FixedUInt<u8, 2>;
856 type U8x4 = FixedUInt<u8, 4>;
857 type U16x2 = FixedUInt<u16, 2>;
858
859 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
861 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
862 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
863
864 test_unbounded(1u8, 4, 16u8, 0u8);
866 test_unbounded(1u16, 4, 16u16, 0u16);
867 test_unbounded(1u32, 4, 16u32, 0u32);
868
869 test_unbounded(1u8, 8, 0u8, 0u8);
871 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
872 }
873}