1use super::{FixedUInt, MachineWord, const_shl_ct, const_shl_impl, const_shr_ct, const_shr_impl};
2
3use crate::machineword::ConstMachineWord;
4use const_num_traits::{
5 CheckedShl, CheckedShr, ConstZero, OverflowingShl, OverflowingShr, UnboundedShl, UnboundedShr,
6 WrappingShl, WrappingShr,
7};
8use const_num_traits::{Nct, Personality, PersonalityTag};
9
10c0nst::c0nst! {
11 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Not for FixedUInt<T, N, P> {
12 type Output = Self;
13 fn not(self) -> Self::Output {
14 let mut ret = <Self as ConstZero>::ZERO;
15 let mut i = 0;
16 while i < N {
17 ret.array[i] = !self.array[i];
18 i += 1;
19 }
20 ret
21 }
22 }
23
24 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Not for &FixedUInt<T, N, P> {
25 type Output = FixedUInt<T, N, P>;
26 fn not(self) -> Self::Output {
27 <FixedUInt<T, N, P> as core::ops::Not>::not(FixedUInt::from_array(self.array))
28 }
29 }
30
31 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
32 type Output = FixedUInt<T, N, P>;
33 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
34 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
35 let mut i = 0;
36 while i < N {
37 ret.array[i] = self.array[i] & other.array[i];
38 i += 1;
39 }
40 ret
41 }
42 }
43
44 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd for FixedUInt<T, N, P> {
45 type Output = Self;
46 fn bitand(self, other: Self) -> Self::Output {
47 (&self).bitand(&other)
48 }
49 }
50
51 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
52 type Output = Self;
53 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
54 (&self).bitand(other)
55 }
56 }
57
58 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
59 type Output = FixedUInt<T, N, P>;
60 fn bitand(self, other: FixedUInt<T, N, P>) -> Self::Output {
61 self.bitand(&other)
62 }
63 }
64
65 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAndAssign for FixedUInt<T, N, P> {
66 fn bitand_assign(&mut self, other: Self) {
67 let mut i = 0;
68 while i < N {
69 self.array[i] &= other.array[i];
70 i += 1;
71 }
72 }
73 }
74
75 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAndAssign<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
76 fn bitand_assign(&mut self, other: &FixedUInt<T, N, P>) {
77 let mut i = 0;
78 while i < N {
79 self.array[i] &= other.array[i];
80 i += 1;
81 }
82 }
83 }
84
85 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
86 type Output = FixedUInt<T, N, P>;
87 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
88 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
89 let mut i = 0;
90 while i < N {
91 ret.array[i] = self.array[i] | other.array[i];
92 i += 1;
93 }
94 ret
95 }
96 }
97
98 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr for FixedUInt<T, N, P> {
99 type Output = Self;
100 fn bitor(self, other: Self) -> Self::Output {
101 (&self).bitor(&other)
102 }
103 }
104
105 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
106 type Output = Self;
107 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
108 (&self).bitor(other)
109 }
110 }
111
112 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
113 type Output = FixedUInt<T, N, P>;
114 fn bitor(self, other: FixedUInt<T, N, P>) -> Self::Output {
115 self.bitor(&other)
116 }
117 }
118
119 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOrAssign for FixedUInt<T, N, P> {
120 fn bitor_assign(&mut self, other: Self) {
121 let mut i = 0;
122 while i < N {
123 self.array[i] |= other.array[i];
124 i += 1;
125 }
126 }
127 }
128
129 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOrAssign<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
130 fn bitor_assign(&mut self, other: &FixedUInt<T, N, P>) {
131 let mut i = 0;
132 while i < N {
133 self.array[i] |= other.array[i];
134 i += 1;
135 }
136 }
137 }
138
139 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
140 type Output = FixedUInt<T, N, P>;
141 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
142 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
143 let mut i = 0;
144 while i < N {
145 ret.array[i] = self.array[i] ^ other.array[i];
146 i += 1;
147 }
148 ret
149 }
150 }
151
152 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor for FixedUInt<T, N, P> {
153 type Output = Self;
154 fn bitxor(self, other: Self) -> Self::Output {
155 (&self).bitxor(&other)
156 }
157 }
158
159 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
160 type Output = Self;
161 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
162 (&self).bitxor(other)
163 }
164 }
165
166 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
167 type Output = FixedUInt<T, N, P>;
168 fn bitxor(self, other: FixedUInt<T, N, P>) -> Self::Output {
169 self.bitxor(&other)
170 }
171 }
172
173 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXorAssign for FixedUInt<T, N, P> {
174 fn bitxor_assign(&mut self, other: Self) {
175 let mut i = 0;
176 while i < N {
177 self.array[i] ^= other.array[i];
178 i += 1;
179 }
180 }
181 }
182
183 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXorAssign<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
184 fn bitxor_assign(&mut self, other: &FixedUInt<T, N, P>) {
185 let mut i = 0;
186 while i < N {
187 self.array[i] ^= other.array[i];
188 i += 1;
189 }
190 }
191 }
192
193 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for FixedUInt<T, N, P> {
195 type Output = Self;
196 fn shl(self, bits: usize) -> Self::Output {
197 let mut result = self;
198 match P::TAG {
199 PersonalityTag::Nct => const_shl_impl(&mut result, bits),
200 PersonalityTag::Ct => const_shl_ct(&mut result, bits),
201 }
202 result
203 }
204 }
205
206 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for FixedUInt<T, N, P> {
207 type Output = Self;
208 fn shr(self, bits: usize) -> Self::Output {
209 let mut result = self;
210 match P::TAG {
211 PersonalityTag::Nct => const_shr_impl(&mut result, bits),
212 PersonalityTag::Ct => const_shr_ct(&mut result, bits),
213 }
214 result
215 }
216 }
217
218 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for FixedUInt<T, N, P> {
219 type Output = Self;
220 fn shl(self, bits: u32) -> Self::Output {
221 const_unbounded_shl_u32(self, bits)
222 }
223 }
224
225 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for FixedUInt<T, N, P> {
226 type Output = Self;
227 fn shr(self, bits: u32) -> Self::Output {
228 const_unbounded_shr_u32(self, bits)
229 }
230 }
231
232 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for FixedUInt<T, N, P> {
233 type Output = Self;
234 fn shl(self, bits: &usize) -> Self::Output {
235 self.shl(*bits)
236 }
237 }
238
239 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for FixedUInt<T, N, P> {
240 type Output = Self;
241 fn shr(self, bits: &usize) -> Self::Output {
242 self.shr(*bits)
243 }
244 }
245
246 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for FixedUInt<T, N, P> {
247 type Output = Self;
248 fn shl(self, bits: &u32) -> Self::Output {
249 self.shl(*bits)
250 }
251 }
252
253 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for FixedUInt<T, N, P> {
254 type Output = Self;
255 fn shr(self, bits: &u32) -> Self::Output {
256 self.shr(*bits)
257 }
258 }
259
260 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 FixedUInt::from_array(self.array).shl(bits)
265 }
266 }
267
268 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 FixedUInt::from_array(self.array).shr(bits)
272 }
273 }
274
275 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 FixedUInt::from_array(self.array).shl(bits)
279 }
280 }
281
282 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 FixedUInt::from_array(self.array).shr(bits)
286 }
287 }
288
289 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for &FixedUInt<T, N, P> {
290 type Output = FixedUInt<T, N, P>;
291 fn shl(self, bits: &usize) -> Self::Output {
292 FixedUInt::from_array(self.array).shl(*bits)
293 }
294 }
295
296 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for &FixedUInt<T, N, P> {
297 type Output = FixedUInt<T, N, P>;
298 fn shr(self, bits: &usize) -> Self::Output {
299 FixedUInt::from_array(self.array).shr(*bits)
300 }
301 }
302
303 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for &FixedUInt<T, N, P> {
304 type Output = FixedUInt<T, N, P>;
305 fn shl(self, bits: &u32) -> Self::Output {
306 FixedUInt::from_array(self.array).shl(*bits)
307 }
308 }
309
310 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for &FixedUInt<T, N, P> {
311 type Output = FixedUInt<T, N, P>;
312 fn shr(self, bits: &u32) -> Self::Output {
313 FixedUInt::from_array(self.array).shr(*bits)
314 }
315 }
316
317 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<usize> for FixedUInt<T, N, P> {
319 fn shl_assign(&mut self, bits: usize) {
320 match P::TAG {
321 PersonalityTag::Nct => const_shl_impl(self, bits),
322 PersonalityTag::Ct => const_shl_ct(self, bits),
323 }
324 }
325 }
326
327 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<usize> for FixedUInt<T, N, P> {
328 fn shr_assign(&mut self, bits: usize) {
329 match P::TAG {
330 PersonalityTag::Nct => const_shr_impl(self, bits),
331 PersonalityTag::Ct => const_shr_ct(self, bits),
332 }
333 }
334 }
335
336 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<&usize> for FixedUInt<T, N, P> {
337 fn shl_assign(&mut self, bits: &usize) {
338 match P::TAG {
339 PersonalityTag::Nct => const_shl_impl(self, *bits),
340 PersonalityTag::Ct => const_shl_ct(self, *bits),
341 }
342 }
343 }
344
345 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<&usize> for FixedUInt<T, N, P> {
346 fn shr_assign(&mut self, bits: &usize) {
347 match P::TAG {
348 PersonalityTag::Nct => const_shr_impl(self, *bits),
349 PersonalityTag::Ct => const_shr_ct(self, *bits),
350 }
351 }
352 }
353
354 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<u32> for FixedUInt<T, N, P> {
357 fn shl_assign(&mut self, bits: u32) {
358 *self = const_unbounded_shl_u32(*self, bits);
359 }
360 }
361
362 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<u32> for FixedUInt<T, N, P> {
363 fn shr_assign(&mut self, bits: u32) {
364 *self = const_unbounded_shr_u32(*self, bits);
365 }
366 }
367
368 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<&u32> for FixedUInt<T, N, P> {
369 fn shl_assign(&mut self, bits: &u32) {
370 *self = const_unbounded_shl_u32(*self, *bits);
371 }
372 }
373
374 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<&u32> for FixedUInt<T, N, P> {
375 fn shr_assign(&mut self, bits: &u32) {
376 *self = const_unbounded_shr_u32(*self, *bits);
377 }
378 }
379
380 pub(crate) c0nst fn const_unbounded_shl_u32<
384 T: [c0nst] ConstMachineWord + MachineWord,
385 const N: usize,
386 P: Personality,
387 >(
388 target: FixedUInt<T, N, P>,
389 bits: u32,
390 ) -> FixedUInt<T, N, P> {
391 match P::TAG {
392 PersonalityTag::Nct => {
393 let (shift, overflow) =
394 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
395 if overflow {
396 <FixedUInt<T, N, P> as ConstZero>::ZERO
397 } else {
398 target << shift
399 }
400 }
401 PersonalityTag::Ct => {
402 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
416 let capped = const_ct_min_u32(bits, bit_size_u32);
417 target << (capped as usize)
418 }
419 }
420 }
421
422 pub(crate) c0nst fn const_unbounded_shr_u32<
424 T: [c0nst] ConstMachineWord + MachineWord,
425 const N: usize,
426 P: Personality,
427 >(
428 target: FixedUInt<T, N, P>,
429 bits: u32,
430 ) -> FixedUInt<T, N, P> {
431 match P::TAG {
432 PersonalityTag::Nct => {
433 let (shift, overflow) =
434 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
435 if overflow {
436 <FixedUInt<T, N, P> as ConstZero>::ZERO
437 } else {
438 target >> shift
439 }
440 }
441 PersonalityTag::Ct => {
442 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
445 let capped = const_ct_min_u32(bits, bit_size_u32);
446 target >> (capped as usize)
447 }
448 }
449 }
450
451 c0nst fn const_ct_min_u32(bits: u32, cap: u32) -> u32 {
458 let diff = cap.wrapping_sub(bits);
460 let too_big_bit = (diff >> 31) & 1;
461 let too_big_mask = core::hint::black_box(too_big_bit.wrapping_neg());
462 bits ^ (too_big_mask & (bits ^ cap))
465 }
466
467 c0nst fn normalize_shift_amount(bits: u32, bit_size: usize) -> (usize, bool) {
470 let bit_size_u32 = bit_size as u32;
471 if bit_size == 0 {
472 (0, true)
474 } else if bit_size_u32 == 0 {
475 (bits as usize, false)
478 } else if bits >= bit_size_u32 {
479 ((bits % bit_size_u32) as usize, true)
481 } else {
482 (bits as usize, false)
483 }
484 }
485
486 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for FixedUInt<T, N, P> {
487 type Output = FixedUInt<T, N, P>;
488 fn overflowing_shl(self, bits: u32) -> (Self, bool) {
489 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
490 let res = core::ops::Shl::<usize>::shl(self, shift);
491 (res, overflow)
492 }
493 }
494
495 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
496 type Output = FixedUInt<T, N, P>;
497 fn overflowing_shr(self, bits: u32) -> (Self, bool) {
498 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
499 let res = core::ops::Shr::<usize>::shr(self, shift);
500 (res, overflow)
501 }
502 }
503
504 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for FixedUInt<T, N, P> {
505 type Output = FixedUInt<T, N, P>;
506 fn wrapping_shl(self, bits: u32) -> Self {
507 OverflowingShl::overflowing_shl(self, bits).0
508 }
509 }
510
511 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for FixedUInt<T, N, P> {
512 type Output = FixedUInt<T, N, P>;
513 fn wrapping_shr(self, bits: u32) -> Self {
514 OverflowingShr::overflowing_shr(self, bits).0
515 }
516 }
517
518 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for FixedUInt<T, N, P> {
519 type Output = FixedUInt<T, N, P>;
520 fn checked_shl(self, bits: u32) -> Option<Self> {
521 let (res, overflow) = OverflowingShl::overflowing_shl(self, bits);
522 if overflow { None } else { Some(res) }
523 }
524 }
525
526 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for FixedUInt<T, N, P> {
527 type Output = FixedUInt<T, N, P>;
528 fn checked_shr(self, bits: u32) -> Option<Self> {
529 let (res, overflow) = OverflowingShr::overflowing_shr(self, bits);
530 if overflow { None } else { Some(res) }
531 }
532 }
533
534 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for FixedUInt<T, N, P> {
535 type Output = FixedUInt<T, N, P>;
536 fn unbounded_shl(self, rhs: u32) -> Self {
537 const_unbounded_shl_u32(self, rhs)
538 }
539 }
540
541 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for FixedUInt<T, N, P> {
542 type Output = FixedUInt<T, N, P>;
543 fn unbounded_shr(self, rhs: u32) -> Self {
544 const_unbounded_shr_u32(self, rhs)
545 }
546 }
547
548 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for &FixedUInt<T, N, P> {
555 type Output = FixedUInt<T, N, P>;
556 fn overflowing_shl(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
557 <FixedUInt<T, N, P> as OverflowingShl>::overflowing_shl(FixedUInt::from_array(self.array), bits)
558 }
559 }
560
561 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for &FixedUInt<T, N, P> {
562 type Output = FixedUInt<T, N, P>;
563 fn overflowing_shr(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
564 <FixedUInt<T, N, P> as OverflowingShr>::overflowing_shr(FixedUInt::from_array(self.array), bits)
565 }
566 }
567
568 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for &FixedUInt<T, N, P> {
569 type Output = FixedUInt<T, N, P>;
570 fn wrapping_shl(self, bits: u32) -> FixedUInt<T, N, P> {
571 <FixedUInt<T, N, P> as WrappingShl>::wrapping_shl(FixedUInt::from_array(self.array), bits)
572 }
573 }
574
575 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for &FixedUInt<T, N, P> {
576 type Output = FixedUInt<T, N, P>;
577 fn wrapping_shr(self, bits: u32) -> FixedUInt<T, N, P> {
578 <FixedUInt<T, N, P> as WrappingShr>::wrapping_shr(FixedUInt::from_array(self.array), bits)
579 }
580 }
581
582 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for &FixedUInt<T, N, P> {
583 type Output = FixedUInt<T, N, P>;
584 fn checked_shl(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
585 <FixedUInt<T, N, P> as CheckedShl>::checked_shl(FixedUInt::from_array(self.array), bits)
586 }
587 }
588
589 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for &FixedUInt<T, N, P> {
590 type Output = FixedUInt<T, N, P>;
591 fn checked_shr(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
592 <FixedUInt<T, N, P> as CheckedShr>::checked_shr(FixedUInt::from_array(self.array), bits)
593 }
594 }
595
596 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for &FixedUInt<T, N, P> {
597 type Output = FixedUInt<T, N, P>;
598 fn unbounded_shl(self, rhs: u32) -> FixedUInt<T, N, P> {
599 <FixedUInt<T, N, P> as UnboundedShl>::unbounded_shl(FixedUInt::from_array(self.array), rhs)
600 }
601 }
602
603 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for &FixedUInt<T, N, P> {
604 type Output = FixedUInt<T, N, P>;
605 fn unbounded_shr(self, rhs: u32) -> FixedUInt<T, N, P> {
606 <FixedUInt<T, N, P> as UnboundedShr>::unbounded_shr(FixedUInt::from_array(self.array), rhs)
607 }
608 }
609
610 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for FixedUInt<T, N, P> {
624 fn highest_one(self) -> Option<u32> {
625 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
626 if lz as usize == Self::BIT_SIZE {
627 None
628 } else {
629 Some(Self::BIT_SIZE as u32 - 1 - lz)
630 }
631 }
632 }
633
634 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for FixedUInt<T, N, P> {
635 fn lowest_one(self) -> Option<u32> {
636 let tz = <Self as const_num_traits::PrimBits>::trailing_zeros(self);
637 if tz as usize == Self::BIT_SIZE {
638 None
639 } else {
640 Some(tz)
641 }
642 }
643 }
644
645 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for &FixedUInt<T, N, P> {
646 fn highest_one(self) -> Option<u32> {
647 <FixedUInt<T, N, P> as const_num_traits::HighestOne>::highest_one(FixedUInt::from_array(self.array))
648 }
649 }
650
651 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for &FixedUInt<T, N, P> {
652 fn lowest_one(self) -> Option<u32> {
653 <FixedUInt<T, N, P> as const_num_traits::LowestOne>::lowest_one(FixedUInt::from_array(self.array))
654 }
655 }
656
657 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for FixedUInt<T, N, P> {
663 fn bit_width(self) -> u32 {
664 Self::BIT_SIZE as u32 - <Self as const_num_traits::PrimBits>::leading_zeros(self)
665 }
666 }
667
668 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for &FixedUInt<T, N, P> {
669 fn bit_width(self) -> u32 {
670 <FixedUInt<T, N, P> as const_num_traits::BitWidth>::bit_width(FixedUInt::from_array(self.array))
671 }
672 }
673
674 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitsPrecision for FixedUInt<T, N, P> {
681 fn bits_precision(&self) -> u32 {
682 Self::BIT_SIZE as u32
683 }
684 }
685
686 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitsPrecision for &FixedUInt<T, N, P> {
687 fn bits_precision(&self) -> u32 {
688 FixedUInt::<T, N, P>::BIT_SIZE as u32
689 }
690 }
691
692 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::WithPrecision for FixedUInt<T, N, P> {
698 fn widen_to_precision(self, _bits_precision: u32) -> Self {
699 self
700 }
701 }
702
703 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for FixedUInt<T, N, P> {
719 type Output = Self;
720 fn isolate_highest_one(self) -> Self {
721 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
722 if lz as usize == Self::BIT_SIZE {
723 <Self as const_num_traits::ConstZero>::ZERO
725 } else {
726 let pos = Self::BIT_SIZE as u32 - 1 - lz;
727 <Self as const_num_traits::ConstOne>::ONE << (pos as usize)
728 }
729 }
730 }
731
732 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for FixedUInt<T, N, P> {
733 type Output = Self;
734 fn isolate_lowest_one(self) -> Self {
735 let neg = <Self as const_num_traits::WrappingSub>::wrapping_sub(
738 <Self as const_num_traits::ConstZero>::ZERO,
739 self,
740 );
741 self & neg
742 }
743 }
744
745 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for &FixedUInt<T, N, P> {
746 type Output = FixedUInt<T, N, P>;
747 fn isolate_highest_one(self) -> FixedUInt<T, N, P> {
748 <FixedUInt<T, N, P> as const_num_traits::IsolateHighestOne>::isolate_highest_one(FixedUInt::from_array(self.array))
749 }
750 }
751
752 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for &FixedUInt<T, N, P> {
753 type Output = FixedUInt<T, N, P>;
754 fn isolate_lowest_one(self) -> FixedUInt<T, N, P> {
755 <FixedUInt<T, N, P> as const_num_traits::IsolateLowestOne>::isolate_lowest_one(FixedUInt::from_array(self.array))
756 }
757 }
758
759 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for FixedUInt<T, N, P> {
772 type Output = FixedUInt<T, N, P>;
773 fn shl_exact(self, rhs: u32) -> Option<Self> {
774 if (rhs as usize) < Self::BIT_SIZE
775 && rhs <= <Self as const_num_traits::PrimBits>::leading_zeros(self)
776 {
777 Some(self << (rhs as usize))
778 } else {
779 None
780 }
781 }
782 }
783
784 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for FixedUInt<T, N, P> {
785 type Output = FixedUInt<T, N, P>;
786 fn shr_exact(self, rhs: u32) -> Option<Self> {
787 if (rhs as usize) < Self::BIT_SIZE
788 && rhs <= <Self as const_num_traits::PrimBits>::trailing_zeros(self)
789 {
790 Some(self >> (rhs as usize))
791 } else {
792 None
793 }
794 }
795 }
796
797 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for &FixedUInt<T, N, P> {
798 type Output = FixedUInt<T, N, P>;
799 fn shl_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
800 <FixedUInt<T, N, P> as const_num_traits::ShlExact>::shl_exact(FixedUInt::from_array(self.array), rhs)
801 }
802 }
803
804 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for &FixedUInt<T, N, P> {
805 type Output = FixedUInt<T, N, P>;
806 fn shr_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
807 <FixedUInt<T, N, P> as const_num_traits::ShrExact>::shr_exact(FixedUInt::from_array(self.array), rhs)
808 }
809 }
810
811 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for FixedUInt<T, N, P> {
821 type Output = Self;
822 fn funnel_shl(self, rhs: Self, n: u32) -> Self {
823 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shl: n out of range");
824 if n == 0 {
825 self
826 } else {
827 let lo_shift = Self::BIT_SIZE as u32 - n;
828 (self << (n as usize)) | (rhs >> (lo_shift as usize))
829 }
830 }
831 }
832
833 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for FixedUInt<T, N, P> {
834 type Output = Self;
835 fn funnel_shr(self, rhs: Self, n: u32) -> Self {
836 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shr: n out of range");
837 if n == 0 {
838 rhs
839 } else {
840 let hi_shift = Self::BIT_SIZE as u32 - n;
841 (rhs >> (n as usize)) | (self << (hi_shift as usize))
842 }
843 }
844 }
845
846 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for &FixedUInt<T, N, P> {
847 type Output = FixedUInt<T, N, P>;
848 fn funnel_shl(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
849 <FixedUInt<T, N, P> as const_num_traits::FunnelShl>::funnel_shl(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
850 }
851 }
852
853 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for &FixedUInt<T, N, P> {
854 type Output = FixedUInt<T, N, P>;
855 fn funnel_shr(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
856 <FixedUInt<T, N, P> as const_num_traits::FunnelShr>::funnel_shr(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
857 }
858 }
859
860 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for FixedUInt<T, N, Nct> {
870 type Output = Self;
871 fn deposit_bits(self, mask: Self) -> Self {
872 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
875 let mut remaining = mask;
876 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
877 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
878 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
880 if !<Self as const_num_traits::Zero>::is_zero(&(self & bb)) {
881 result |= lowest;
882 }
883 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
884 remaining,
885 <Self as const_num_traits::ConstOne>::ONE,
886 );
887 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
888 }
889 result
890 }
891 }
892
893 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for FixedUInt<T, N, Nct> {
894 type Output = Self;
895 fn extract_bits(self, mask: Self) -> Self {
896 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
899 let mut remaining = mask;
900 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
901 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
902 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
903 if !<Self as const_num_traits::Zero>::is_zero(&(self & lowest)) {
904 result |= bb;
905 }
906 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
907 remaining,
908 <Self as const_num_traits::ConstOne>::ONE,
909 );
910 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
911 }
912 result
913 }
914 }
915
916 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for &FixedUInt<T, N, Nct> {
917 type Output = FixedUInt<T, N, Nct>;
918 fn deposit_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
919 <FixedUInt<T, N, Nct> as const_num_traits::DepositBits>::deposit_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
920 }
921 }
922
923 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for &FixedUInt<T, N, Nct> {
924 type Output = FixedUInt<T, N, Nct>;
925 fn extract_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
926 <FixedUInt<T, N, Nct> as const_num_traits::ExtractBits>::extract_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
927 }
928 }
929}
930
931#[cfg(feature = "num-traits")]
933impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
934 for FixedUInt<T, N, P>
935{
936 fn wrapping_shl(&self, bits: u32) -> Self {
937 <&Self as WrappingShl>::wrapping_shl(self, bits)
938 }
939}
940
941#[cfg(feature = "num-traits")]
942impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
943 for FixedUInt<T, N, P>
944{
945 fn wrapping_shr(&self, bits: u32) -> Self {
946 <&Self as WrappingShr>::wrapping_shr(self, bits)
947 }
948}
949
950#[cfg(feature = "num-traits")]
951impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
952 fn checked_shl(&self, bits: u32) -> Option<Self> {
953 <&Self as CheckedShl>::checked_shl(self, bits)
954 }
955}
956
957#[cfg(feature = "num-traits")]
958impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
959 fn checked_shr(&self, bits: u32) -> Option<Self> {
960 <&Self as CheckedShr>::checked_shr(self, bits)
961 }
962}
963
964#[cfg(test)]
965#[allow(clippy::op_ref)]
968mod tests {
969 use super::*;
970
971 #[test]
972 fn test_bitand_combinations() {
973 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);
979 assert_eq!(a & &b, expected);
981 assert_eq!(&a & b, expected);
983 assert_eq!(&a & &b, expected);
985 }
986
987 #[test]
988 fn test_bitor_combinations() {
989 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);
995 assert_eq!(a | &b, expected);
997 assert_eq!(&a | b, expected);
999 assert_eq!(&a | &b, expected);
1001 }
1002
1003 #[test]
1004 fn test_bitxor_combinations() {
1005 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);
1011 assert_eq!(a ^ &b, expected);
1013 assert_eq!(&a ^ b, expected);
1015 assert_eq!(&a ^ &b, expected);
1017 }
1018
1019 #[test]
1020 fn test_shl_combinations() {
1021 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
1023 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
1027 assert_eq!(a << &shift, expected);
1029 assert_eq!(&a << shift, expected);
1031 assert_eq!(&a << &shift, expected);
1033
1034 let shift32: u32 = 2;
1036 assert_eq!(a << shift32, expected);
1037 assert_eq!(a << &shift32, expected);
1038 assert_eq!(&a << shift32, expected);
1039 assert_eq!(&a << &shift32, expected);
1040 }
1041
1042 #[test]
1043 fn test_shr_combinations() {
1044 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
1046 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
1050 assert_eq!(a >> &shift, expected);
1052 assert_eq!(&a >> shift, expected);
1054 assert_eq!(&a >> &shift, expected);
1056
1057 let shift32: u32 = 2;
1059 assert_eq!(a >> shift32, expected);
1060 assert_eq!(a >> &shift32, expected);
1061 assert_eq!(&a >> shift32, expected);
1062 assert_eq!(&a >> &shift32, expected);
1063 }
1064
1065 #[test]
1066 fn test_const_bitops() {
1067 type TestInt = FixedUInt<u8, 2>;
1068
1069 let a = TestInt::from(0b11001100u8);
1070 let b = TestInt::from(0b10101010u8);
1071
1072 let not_a = !a;
1074 assert_eq!(not_a.array[0], 0b00110011);
1075 assert_eq!(not_a.array[1], 0xFF);
1076
1077 assert_eq!(a & b, TestInt::from(0b10001000u8));
1079
1080 assert_eq!(a | b, TestInt::from(0b11101110u8));
1082
1083 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
1085
1086 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
1088
1089 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
1091
1092 #[cfg(feature = "nightly")]
1093 {
1094 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
1095 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
1096
1097 const NOT_A: TestInt = !A;
1098 const AND_AB: TestInt = A & B;
1099 const OR_AB: TestInt = A | B;
1100 const XOR_AB: TestInt = A ^ B;
1101 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
1102 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
1103
1104 assert_eq!(NOT_A.array[0], 0b00110011);
1105 assert_eq!(AND_AB.array[0], 0b10001000);
1106 assert_eq!(OR_AB.array[0], 0b11101110);
1107 assert_eq!(XOR_AB.array[0], 0b01100110);
1108 assert_eq!(SHL_1.array[0], 16);
1109 assert_eq!(SHR_16.array[0], 4);
1110 }
1111 }
1112
1113 #[test]
1114 fn test_const_shift_traits() {
1115 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = OverflowingShl::overflowing_shl(a, 8);
1120 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
1122
1123 let (res, overflow) = OverflowingShl::overflowing_shl(a, 16);
1124 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
1126
1127 let (res, overflow) = OverflowingShl::overflowing_shl(a, 9);
1128 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = OverflowingShr::overflowing_shr(b, 8);
1134 assert_eq!(res.array, [1, 0]); assert!(!overflow);
1136
1137 let (res, overflow) = OverflowingShr::overflowing_shr(b, 16);
1138 assert_eq!(res.array, [0, 1]); assert!(overflow);
1140
1141 let c = TestInt::from(1u8);
1143 assert_eq!(WrappingShl::wrapping_shl(c, 4).array, [16, 0]);
1144 assert_eq!(WrappingShl::wrapping_shl(c, 16).array, [1, 0]); assert_eq!(WrappingShl::wrapping_shl(c, 17).array, [2, 0]); let d = TestInt::from(0x8000u16);
1149 assert_eq!(WrappingShr::wrapping_shr(d, 4).array, [0, 0x08]);
1150 assert_eq!(WrappingShr::wrapping_shr(d, 16).array, [0, 0x80]); assert_eq!(WrappingShr::wrapping_shr(d, 17).array, [0, 0x40]); let e = TestInt::from(1u8);
1155 assert_eq!(CheckedShl::checked_shl(e, 4), Some(TestInt::from(16u8)));
1156 assert_eq!(
1157 CheckedShl::checked_shl(e, 15),
1158 Some(TestInt::from(0x8000u16))
1159 );
1160 assert_eq!(CheckedShl::checked_shl(e, 16), None); let f = TestInt::from(0x8000u16);
1164 assert_eq!(CheckedShr::checked_shr(f, 15), Some(TestInt::from(1u8)));
1165 assert_eq!(CheckedShr::checked_shr(f, 16), None); let g = TestInt::from(42u8);
1169 assert_eq!(OverflowingShl::overflowing_shl(g, 0), (g, false));
1170 assert_eq!(OverflowingShr::overflowing_shr(g, 0), (g, false));
1171 assert_eq!(WrappingShl::wrapping_shl(g, 0), g);
1172 assert_eq!(WrappingShr::wrapping_shr(g, 0), g);
1173 assert_eq!(CheckedShl::checked_shl(g, 0), Some(g));
1174 assert_eq!(CheckedShr::checked_shr(g, 0), Some(g));
1175 }
1176
1177 #[test]
1178 fn test_const_shift_traits_n0() {
1179 type ZeroInt = FixedUInt<u8, 0>;
1181 let z = ZeroInt::from_array([]);
1182
1183 assert_eq!(OverflowingShl::overflowing_shl(z, 0), (z, true));
1185 assert_eq!(OverflowingShr::overflowing_shr(z, 0), (z, true));
1186 assert_eq!(WrappingShl::wrapping_shl(z, 0), z);
1187 assert_eq!(WrappingShr::wrapping_shr(z, 0), z);
1188 assert_eq!(CheckedShl::checked_shl(z, 0), None);
1189 assert_eq!(CheckedShr::checked_shr(z, 0), None);
1190 }
1191
1192 #[test]
1193 #[cfg(feature = "num-traits")]
1194 fn test_num_traits_shift_wrappers() {
1195 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
1196
1197 type TestInt = FixedUInt<u8, 2>;
1198
1199 let a = TestInt::from(1u8);
1200
1201 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
1203 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
1207 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
1208
1209 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
1211 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
1212
1213 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
1215 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
1216 }
1217
1218 #[test]
1219 fn test_unbounded_shift() {
1220 type U16 = FixedUInt<u8, 2>;
1221
1222 let one = U16::from(1u8);
1223
1224 assert_eq!(UnboundedShl::unbounded_shl(one, 0), one);
1226 assert_eq!(UnboundedShl::unbounded_shl(one, 4), U16::from(16u8));
1227 assert_eq!(UnboundedShl::unbounded_shl(one, 15), U16::from(0x8000u16));
1228
1229 assert_eq!(UnboundedShr::unbounded_shr(U16::from(0x8000u16), 15), one);
1230 assert_eq!(UnboundedShr::unbounded_shr(U16::from(16u8), 4), one);
1231
1232 assert_eq!(UnboundedShl::unbounded_shl(one, 16), U16::from(0u8));
1234 assert_eq!(
1235 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 16),
1236 U16::from(0u8)
1237 );
1238
1239 assert_eq!(
1241 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 17),
1242 U16::from(0u8)
1243 );
1244 assert_eq!(
1245 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 100),
1246 U16::from(0u8)
1247 );
1248 assert_eq!(
1249 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 17),
1250 U16::from(0u8)
1251 );
1252 assert_eq!(
1253 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 100),
1254 U16::from(0u8)
1255 );
1256
1257 type U32 = FixedUInt<u8, 4>;
1259 let one32 = U32::from(1u8);
1260 assert_eq!(
1261 UnboundedShl::unbounded_shl(one32, 31),
1262 U32::from(0x80000000u32)
1263 );
1264 assert_eq!(UnboundedShl::unbounded_shl(one32, 32), U32::from(0u8));
1265 assert_eq!(
1266 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 31),
1267 one32
1268 );
1269 assert_eq!(
1270 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 32),
1271 U32::from(0u8)
1272 );
1273 }
1274
1275 #[test]
1276 fn test_unbounded_shift_polymorphic() {
1277 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
1278 where
1279 T: UnboundedShl<Output = T> + UnboundedShr<Output = T> + Eq + core::fmt::Debug + Copy,
1280 {
1281 assert_eq!(UnboundedShl::unbounded_shl(val, shift), expected_shl);
1282 assert_eq!(UnboundedShr::unbounded_shr(val, shift), expected_shr);
1283 }
1284
1285 type U8x2 = FixedUInt<u8, 2>;
1287 type U8x4 = FixedUInt<u8, 4>;
1288 type U16x2 = FixedUInt<u16, 2>;
1289
1290 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
1292 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
1293 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
1294
1295 test_unbounded(1u8, 4, 16u8, 0u8);
1297 test_unbounded(1u16, 4, 16u16, 0u16);
1298 test_unbounded(1u32, 4, 16u32, 0u32);
1299
1300 test_unbounded(1u8, 8, 0u8, 0u8);
1302 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
1303 }
1304
1305 #[test]
1306 fn test_bit_width() {
1307 use const_num_traits::BitWidth;
1308 type U16 = FixedUInt<u8, 2>;
1309 assert_eq!(BitWidth::bit_width(U16::from(0u8)), 0);
1310 assert_eq!(BitWidth::bit_width(U16::from(1u8)), 1);
1311 assert_eq!(BitWidth::bit_width(U16::from(2u8)), 2);
1312 assert_eq!(BitWidth::bit_width(U16::from(3u8)), 2);
1313 assert_eq!(BitWidth::bit_width(U16::from(255u8)), 8);
1314 assert_eq!(BitWidth::bit_width(U16::from(256u16)), 9);
1315 assert_eq!(BitWidth::bit_width(U16::from(0xFFFFu16)), 16);
1316 }
1317
1318 #[test]
1319 fn test_bits_precision() {
1320 use const_num_traits::BitsPrecision;
1321 type U16 = FixedUInt<u8, 2>;
1323 type U32 = FixedUInt<u32, 1>;
1324 assert_eq!(BitsPrecision::bits_precision(&U16::from(0u8)), 16);
1325 assert_eq!(BitsPrecision::bits_precision(&U16::from(0xFFFFu16)), 16);
1326 assert_eq!(BitsPrecision::bits_precision(&U32::from(0u8)), 32);
1327 assert_eq!(BitsPrecision::bits_precision(&U32::from(7u8)), 32);
1328 }
1329
1330 #[test]
1331 fn test_highest_lowest_one() {
1332 use const_num_traits::{HighestOne, LowestOne};
1333 type U16 = FixedUInt<u8, 2>;
1334 assert_eq!(HighestOne::highest_one(U16::from(0u8)), None);
1335 assert_eq!(HighestOne::highest_one(U16::from(1u8)), Some(0));
1336 assert_eq!(HighestOne::highest_one(U16::from(0b1010_0000u8)), Some(7));
1337 assert_eq!(HighestOne::highest_one(U16::from(0x8000u16)), Some(15));
1338
1339 assert_eq!(LowestOne::lowest_one(U16::from(0u8)), None);
1340 assert_eq!(LowestOne::lowest_one(U16::from(1u8)), Some(0));
1341 assert_eq!(LowestOne::lowest_one(U16::from(0b0010_1000u8)), Some(3));
1342 assert_eq!(LowestOne::lowest_one(U16::from(0x8000u16)), Some(15));
1343 }
1344
1345 #[test]
1346 fn test_isolate_highest_lowest_one() {
1347 use const_num_traits::{IsolateHighestOne, IsolateLowestOne};
1348 type U16 = FixedUInt<u8, 2>;
1349 assert_eq!(
1351 IsolateHighestOne::isolate_highest_one(U16::from(0u8)),
1352 U16::from(0u8)
1353 );
1354 assert_eq!(
1355 IsolateLowestOne::isolate_lowest_one(U16::from(0u8)),
1356 U16::from(0u8)
1357 );
1358 assert_eq!(
1360 IsolateHighestOne::isolate_highest_one(U16::from(0b1010_0000u8)),
1361 U16::from(0b1000_0000u8)
1362 );
1363 assert_eq!(
1364 IsolateLowestOne::isolate_lowest_one(U16::from(0b1010_1000u8)),
1365 U16::from(0b0000_1000u8)
1366 );
1367 let p: U16 = U16::from(0x0100u16);
1369 assert_eq!(IsolateHighestOne::isolate_highest_one(p), p);
1370 assert_eq!(IsolateLowestOne::isolate_lowest_one(p), p);
1371 }
1372
1373 #[test]
1374 fn test_shl_shr_exact() {
1375 use const_num_traits::{ShlExact, ShrExact};
1376 type U16 = FixedUInt<u8, 2>;
1377 assert_eq!(
1379 ShlExact::shl_exact(U16::from(1u8), 4),
1380 Some(U16::from(16u8))
1381 );
1382 assert_eq!(ShlExact::shl_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1383 assert_eq!(ShlExact::shl_exact(U16::from(0x8000u16), 1), None);
1385 assert_eq!(ShlExact::shl_exact(U16::from(1u8), 16), None);
1387
1388 assert_eq!(
1390 ShrExact::shr_exact(U16::from(16u8), 4),
1391 Some(U16::from(1u8))
1392 );
1393 assert_eq!(ShrExact::shr_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1394 assert_eq!(ShrExact::shr_exact(U16::from(0b0001u8), 1), None);
1396 assert_eq!(ShrExact::shr_exact(U16::from(0b0011u8), 1), None);
1397 assert_eq!(ShrExact::shr_exact(U16::from(1u8), 16), None);
1399 }
1400
1401 #[test]
1402 #[allow(clippy::needless_borrows_for_generic_args)]
1403 fn test_ref_receivers_compile_through() {
1404 use const_num_traits::{BitWidth, IsolateHighestOne, IsolateLowestOne, ShlExact, ShrExact};
1405 type U16 = FixedUInt<u8, 2>;
1406 let v = U16::from(0b0010_1000u8);
1407 assert_eq!(BitWidth::bit_width(&v), 6);
1408 assert_eq!(
1409 IsolateHighestOne::isolate_highest_one(&v),
1410 U16::from(0b0010_0000u8)
1411 );
1412 assert_eq!(
1413 IsolateLowestOne::isolate_lowest_one(&v),
1414 U16::from(0b0000_1000u8)
1415 );
1416 assert_eq!(ShlExact::shl_exact(&v, 2), Some(U16::from(0b1010_0000u8)));
1417 assert_eq!(ShrExact::shr_exact(&v, 3), Some(U16::from(0b0000_0101u8)));
1418 }
1419
1420 #[test]
1421 fn test_funnel_shifts() {
1422 use const_num_traits::{FunnelShl, FunnelShr};
1423 type U16 = FixedUInt<u8, 2>;
1424
1425 assert_eq!(
1427 FunnelShl::funnel_shl(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1428 U16::from(0x0003u16),
1429 );
1430 assert_eq!(
1432 FunnelShl::funnel_shl(U16::from(0xABCDu16), U16::from(0xFFFFu16), 0),
1433 U16::from(0xABCDu16),
1434 );
1435 assert_eq!(
1437 FunnelShr::funnel_shr(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1438 U16::from(0xC000u16),
1439 );
1440 assert_eq!(
1442 FunnelShr::funnel_shr(U16::from(0xABCDu16), U16::from(0x1234u16), 0),
1443 U16::from(0x1234u16),
1444 );
1445
1446 let hi = U16::from(0x0001u16);
1448 let lo = U16::from(0x8000u16);
1449 assert_eq!(FunnelShl::funnel_shl(&hi, &lo, 1), U16::from(0x0003u16));
1450 assert_eq!(FunnelShr::funnel_shr(&hi, &lo, 1), U16::from(0xC000u16));
1451 }
1452
1453 #[test]
1454 #[should_panic(expected = "funnel_shl: n out of range")]
1455 fn test_funnel_shl_panics_at_bit_size() {
1456 use const_num_traits::FunnelShl;
1457 type U16 = FixedUInt<u8, 2>;
1458 let _ = FunnelShl::funnel_shl(U16::from(1u8), U16::from(0u8), 16);
1459 }
1460
1461 #[test]
1462 fn test_deposit_extract_bits() {
1463 use const_num_traits::Nct;
1464 use const_num_traits::{DepositBits, ExtractBits};
1465 type U16 = FixedUInt<u8, 2, Nct>;
1466
1467 assert_eq!(
1470 DepositBits::deposit_bits(U16::from(0b101u8), U16::from(0b1111_0000u8)),
1471 U16::from(0b0101_0000u8),
1472 );
1473 assert_eq!(
1475 ExtractBits::extract_bits(U16::from(0b0101_0011u8), U16::from(0b1111_0000u8)),
1476 U16::from(0b101u8),
1477 );
1478
1479 assert_eq!(
1481 DepositBits::deposit_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1482 U16::from(0u8),
1483 );
1484 assert_eq!(
1485 ExtractBits::extract_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1486 U16::from(0u8),
1487 );
1488
1489 assert_eq!(
1491 DepositBits::deposit_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1492 U16::from(0xABCDu16),
1493 );
1494 assert_eq!(
1495 ExtractBits::extract_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1496 U16::from(0xABCDu16),
1497 );
1498
1499 let mask = U16::from(0b1010_1010u8);
1503 let v = U16::from(0b1111_1111u8);
1504 let extracted = ExtractBits::extract_bits(v, mask);
1505 let redeposited = DepositBits::deposit_bits(extracted, mask);
1506 assert_eq!(redeposited, v & mask);
1507
1508 let v_ref = U16::from(0b0110_0110u8);
1510 let m_ref = U16::from(0b1111_0000u8);
1511 assert_eq!(
1512 ExtractBits::extract_bits(&v_ref, &m_ref),
1513 U16::from(0b0110u8),
1514 );
1515 assert_eq!(
1516 DepositBits::deposit_bits(&U16::from(0b101u8), &m_ref),
1517 U16::from(0b0101_0000u8),
1518 );
1519 }
1520
1521 c0nst::c0nst! {
1531 pub c0nst fn const_overflowing_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> (FixedUInt<T, N, P>, bool) {
1532 OverflowingShl::overflowing_shl(v, bits)
1533 }
1534 pub c0nst fn const_overflowing_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> (FixedUInt<T, N, P>, bool) {
1535 OverflowingShr::overflowing_shr(v, bits)
1536 }
1537 pub c0nst fn const_wrapping_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
1538 WrappingShl::wrapping_shl(v, bits)
1539 }
1540 pub c0nst fn const_wrapping_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
1541 WrappingShr::wrapping_shr(v, bits)
1542 }
1543 pub c0nst fn const_checked_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
1544 CheckedShl::checked_shl(v, bits)
1545 }
1546 pub c0nst fn const_checked_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
1547 CheckedShr::checked_shr(v, bits)
1548 }
1549 pub c0nst fn const_unbounded_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
1550 UnboundedShl::unbounded_shl(v, bits)
1551 }
1552 pub c0nst fn const_unbounded_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
1553 UnboundedShr::unbounded_shr(v, bits)
1554 }
1555 pub c0nst fn const_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1556 const_num_traits::HighestOne::highest_one(v)
1557 }
1558 pub c0nst fn const_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1559 const_num_traits::LowestOne::lowest_one(v)
1560 }
1561 pub c0nst fn const_bit_width<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
1562 const_num_traits::BitWidth::bit_width(v)
1563 }
1564 pub c0nst fn const_isolate_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
1565 const_num_traits::IsolateHighestOne::isolate_highest_one(v)
1566 }
1567 pub c0nst fn const_isolate_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
1568 const_num_traits::IsolateLowestOne::isolate_lowest_one(v)
1569 }
1570 pub c0nst fn const_shl_exact<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
1571 const_num_traits::ShlExact::shl_exact(v, bits)
1572 }
1573 pub c0nst fn const_shr_exact<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
1574 const_num_traits::ShrExact::shr_exact(v, bits)
1575 }
1576 pub c0nst fn const_funnel_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(hi: FixedUInt<T, N, P>, lo: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
1577 const_num_traits::FunnelShl::funnel_shl(hi, lo, n)
1578 }
1579 pub c0nst fn const_funnel_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(hi: FixedUInt<T, N, P>, lo: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
1580 const_num_traits::FunnelShr::funnel_shr(hi, lo, n)
1581 }
1582 pub c0nst fn const_deposit_bits<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(v: FixedUInt<T, N, Nct>, mask: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
1583 const_num_traits::DepositBits::deposit_bits(v, mask)
1584 }
1585 pub c0nst fn const_extract_bits<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(v: FixedUInt<T, N, Nct>, mask: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
1586 const_num_traits::ExtractBits::extract_bits(v, mask)
1587 }
1588 }
1589
1590 #[test]
1591 fn nightly_const_eval_bit_traits() {
1592 type U16 = FixedUInt<u8, 2>;
1593
1594 let v = U16::from(1u8);
1596 assert_eq!(const_overflowing_shl(v, 4), (U16::from(16u8), false));
1597 assert_eq!(const_wrapping_shl(v, 4), U16::from(16u8));
1598 assert_eq!(const_checked_shl(v, 16), None);
1599 assert_eq!(const_bit_width(U16::from(0xFFu8)), 8);
1600
1601 #[cfg(feature = "nightly")]
1603 {
1604 const V: U16 = FixedUInt::from_array([1, 0]);
1605 const V_FF: U16 = FixedUInt::from_array([0xFF, 0]);
1606 const V_MASK: U16 = FixedUInt::from_array([0b1010_1000, 0]);
1607 const HI: U16 = FixedUInt::from_array([1, 0]);
1608 const LO: U16 = FixedUInt::from_array([0, 0x80]);
1609
1610 const OSHL: (U16, bool) = const_overflowing_shl(V, 4);
1611 const OSHR: (U16, bool) = const_overflowing_shr(V_FF, 4);
1612 const WSHL: U16 = const_wrapping_shl(V, 4);
1613 const WSHR: U16 = const_wrapping_shr(V_FF, 4);
1614 const CSHL: Option<U16> = const_checked_shl(V, 16);
1615 const CSHR: Option<U16> = const_checked_shr(V, 4);
1616 const USHL: U16 = const_unbounded_shl(V, 8);
1617 const USHR: U16 = const_unbounded_shr(V_FF, 4);
1618 const HI_ONE: Option<u32> = const_highest_one(V_FF);
1619 const LO_ONE: Option<u32> = const_lowest_one(V_MASK);
1620 const BW: u32 = const_bit_width(V_FF);
1621 const IH: U16 = const_isolate_highest_one(V_MASK);
1622 const IL: U16 = const_isolate_lowest_one(V_MASK);
1623 const SHLEX: Option<U16> = const_shl_exact(V, 4);
1624 const SHREX: Option<U16> = const_shr_exact(FixedUInt::from_array([16, 0]), 4);
1625 const FSHL: U16 = const_funnel_shl(HI, LO, 1);
1626 const FSHR: U16 = const_funnel_shr(HI, LO, 1);
1627 const DEP: U16 = const_deposit_bits(
1628 FixedUInt::from_array([0b101, 0]),
1629 FixedUInt::from_array([0b1111_0000, 0]),
1630 );
1631 const EXT: U16 = const_extract_bits(
1632 FixedUInt::from_array([0b0101_0011, 0]),
1633 FixedUInt::from_array([0b1111_0000, 0]),
1634 );
1635
1636 assert_eq!(OSHL.0.array, [16, 0]);
1638 assert!(!OSHL.1);
1639 assert_eq!(OSHR.0.array, [0x0F, 0]);
1640 assert!(!OSHR.1);
1641 assert_eq!(WSHL.array, [16, 0]);
1642 assert_eq!(WSHR.array, [0x0F, 0]);
1643 assert!(CSHL.is_none());
1644 assert!(CSHR.is_some());
1645 assert_eq!(USHL.array, [0, 1]);
1646 assert_eq!(USHR.array, [0x0F, 0]);
1647 assert_eq!(HI_ONE, Some(7));
1648 assert_eq!(LO_ONE, Some(3));
1649 assert_eq!(BW, 8);
1650 assert_eq!(IH.array, [0b1000_0000, 0]);
1651 assert_eq!(IL.array, [0b0000_1000, 0]);
1652 assert!(SHLEX.is_some());
1653 assert!(SHREX.is_some());
1654 assert_eq!(FSHL.array, [0x03, 0]);
1655 assert_eq!(FSHR.array, [0x00, 0xC0]);
1656 assert_eq!(DEP.array, [0b0101_0000, 0]);
1657 assert_eq!(EXT.array, [0b101, 0]);
1658 }
1659 }
1660}