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::BitAnd<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
25 type Output = FixedUInt<T, N, P>;
26 fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
27 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
28 let mut i = 0;
29 while i < N {
30 ret.array[i] = self.array[i] & other.array[i];
31 i += 1;
32 }
33 ret
34 }
35 }
36
37 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd for FixedUInt<T, N, P> {
38 type Output = Self;
39 fn bitand(self, other: Self) -> Self::Output {
40 (&self).bitand(&other)
41 }
42 }
43
44 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
45 type Output = Self;
46 fn bitand(self, other: &FixedUInt<T, N, P>) -> 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 = FixedUInt<T, N, P>;
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::BitAndAssign for FixedUInt<T, N, P> {
59 fn bitand_assign(&mut self, other: Self) {
60 let mut i = 0;
61 while i < N {
62 self.array[i] &= other.array[i];
63 i += 1;
64 }
65 }
66 }
67
68 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
69 type Output = FixedUInt<T, N, P>;
70 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
71 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
72 let mut i = 0;
73 while i < N {
74 ret.array[i] = self.array[i] | other.array[i];
75 i += 1;
76 }
77 ret
78 }
79 }
80
81 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr for FixedUInt<T, N, P> {
82 type Output = Self;
83 fn bitor(self, other: Self) -> Self::Output {
84 (&self).bitor(&other)
85 }
86 }
87
88 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
89 type Output = Self;
90 fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
91 (&self).bitor(other)
92 }
93 }
94
95 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
96 type Output = FixedUInt<T, N, P>;
97 fn bitor(self, other: FixedUInt<T, N, P>) -> Self::Output {
98 self.bitor(&other)
99 }
100 }
101
102 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOrAssign for FixedUInt<T, N, P> {
103 fn bitor_assign(&mut self, other: Self) {
104 let mut i = 0;
105 while i < N {
106 self.array[i] |= other.array[i];
107 i += 1;
108 }
109 }
110 }
111
112 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
113 type Output = FixedUInt<T, N, P>;
114 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
115 let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
116 let mut i = 0;
117 while i < N {
118 ret.array[i] = self.array[i] ^ other.array[i];
119 i += 1;
120 }
121 ret
122 }
123 }
124
125 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor for FixedUInt<T, N, P> {
126 type Output = Self;
127 fn bitxor(self, other: Self) -> Self::Output {
128 (&self).bitxor(&other)
129 }
130 }
131
132 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
133 type Output = Self;
134 fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
135 (&self).bitxor(other)
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 self.bitxor(&other)
143 }
144 }
145
146 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXorAssign for FixedUInt<T, N, P> {
147 fn bitxor_assign(&mut self, other: Self) {
148 let mut i = 0;
149 while i < N {
150 self.array[i] ^= other.array[i];
151 i += 1;
152 }
153 }
154 }
155
156 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for FixedUInt<T, N, P> {
158 type Output = Self;
159 fn shl(self, bits: usize) -> Self::Output {
160 let mut result = self;
161 match P::TAG {
162 PersonalityTag::Nct => const_shl_impl(&mut result, bits),
163 PersonalityTag::Ct => const_shl_ct(&mut result, bits),
164 }
165 result
166 }
167 }
168
169 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for FixedUInt<T, N, P> {
170 type Output = Self;
171 fn shr(self, bits: usize) -> Self::Output {
172 let mut result = self;
173 match P::TAG {
174 PersonalityTag::Nct => const_shr_impl(&mut result, bits),
175 PersonalityTag::Ct => const_shr_ct(&mut result, bits),
176 }
177 result
178 }
179 }
180
181 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for FixedUInt<T, N, P> {
182 type Output = Self;
183 fn shl(self, bits: u32) -> Self::Output {
184 const_unbounded_shl_u32(self, bits)
185 }
186 }
187
188 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for FixedUInt<T, N, P> {
189 type Output = Self;
190 fn shr(self, bits: u32) -> Self::Output {
191 const_unbounded_shr_u32(self, bits)
192 }
193 }
194
195 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for FixedUInt<T, N, P> {
196 type Output = Self;
197 fn shl(self, bits: &usize) -> Self::Output {
198 self.shl(*bits)
199 }
200 }
201
202 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for FixedUInt<T, N, P> {
203 type Output = Self;
204 fn shr(self, bits: &usize) -> Self::Output {
205 self.shr(*bits)
206 }
207 }
208
209 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for FixedUInt<T, N, P> {
210 type Output = Self;
211 fn shl(self, bits: &u32) -> Self::Output {
212 self.shl(*bits)
213 }
214 }
215
216 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for FixedUInt<T, N, P> {
217 type Output = Self;
218 fn shr(self, bits: &u32) -> Self::Output {
219 self.shr(*bits)
220 }
221 }
222
223 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for &FixedUInt<T, N, P> {
225 type Output = FixedUInt<T, N, P>;
226 fn shl(self, bits: usize) -> Self::Output {
227 FixedUInt::from_array(self.array).shl(bits)
228 }
229 }
230
231 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for &FixedUInt<T, N, P> {
232 type Output = FixedUInt<T, N, P>;
233 fn shr(self, bits: usize) -> Self::Output {
234 FixedUInt::from_array(self.array).shr(bits)
235 }
236 }
237
238 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for &FixedUInt<T, N, P> {
239 type Output = FixedUInt<T, N, P>;
240 fn shl(self, bits: u32) -> Self::Output {
241 FixedUInt::from_array(self.array).shl(bits)
242 }
243 }
244
245 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for &FixedUInt<T, N, P> {
246 type Output = FixedUInt<T, N, P>;
247 fn shr(self, bits: u32) -> Self::Output {
248 FixedUInt::from_array(self.array).shr(bits)
249 }
250 }
251
252 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for &FixedUInt<T, N, P> {
253 type Output = FixedUInt<T, N, P>;
254 fn shl(self, bits: &usize) -> Self::Output {
255 FixedUInt::from_array(self.array).shl(*bits)
256 }
257 }
258
259 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for &FixedUInt<T, N, P> {
260 type Output = FixedUInt<T, N, P>;
261 fn shr(self, bits: &usize) -> Self::Output {
262 FixedUInt::from_array(self.array).shr(*bits)
263 }
264 }
265
266 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for &FixedUInt<T, N, P> {
267 type Output = FixedUInt<T, N, P>;
268 fn shl(self, bits: &u32) -> Self::Output {
269 FixedUInt::from_array(self.array).shl(*bits)
270 }
271 }
272
273 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for &FixedUInt<T, N, P> {
274 type Output = FixedUInt<T, N, P>;
275 fn shr(self, bits: &u32) -> Self::Output {
276 FixedUInt::from_array(self.array).shr(*bits)
277 }
278 }
279
280 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<usize> for FixedUInt<T, N, P> {
282 fn shl_assign(&mut self, bits: usize) {
283 match P::TAG {
284 PersonalityTag::Nct => const_shl_impl(self, bits),
285 PersonalityTag::Ct => const_shl_ct(self, bits),
286 }
287 }
288 }
289
290 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<usize> for FixedUInt<T, N, P> {
291 fn shr_assign(&mut self, bits: usize) {
292 match P::TAG {
293 PersonalityTag::Nct => const_shr_impl(self, bits),
294 PersonalityTag::Ct => const_shr_ct(self, bits),
295 }
296 }
297 }
298
299 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<&usize> for FixedUInt<T, N, P> {
300 fn shl_assign(&mut self, bits: &usize) {
301 match P::TAG {
302 PersonalityTag::Nct => const_shl_impl(self, *bits),
303 PersonalityTag::Ct => const_shl_ct(self, *bits),
304 }
305 }
306 }
307
308 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<&usize> for FixedUInt<T, N, P> {
309 fn shr_assign(&mut self, bits: &usize) {
310 match P::TAG {
311 PersonalityTag::Nct => const_shr_impl(self, *bits),
312 PersonalityTag::Ct => const_shr_ct(self, *bits),
313 }
314 }
315 }
316
317 pub(crate) c0nst fn const_unbounded_shl_u32<
321 T: [c0nst] ConstMachineWord + MachineWord,
322 const N: usize,
323 P: Personality,
324 >(
325 target: FixedUInt<T, N, P>,
326 bits: u32,
327 ) -> FixedUInt<T, N, P> {
328 match P::TAG {
329 PersonalityTag::Nct => {
330 let (shift, overflow) =
331 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
332 if overflow {
333 <FixedUInt<T, N, P> as ConstZero>::ZERO
334 } else {
335 target << shift
336 }
337 }
338 PersonalityTag::Ct => {
339 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
353 let capped = const_ct_min_u32(bits, bit_size_u32);
354 target << (capped as usize)
355 }
356 }
357 }
358
359 pub(crate) c0nst fn const_unbounded_shr_u32<
361 T: [c0nst] ConstMachineWord + MachineWord,
362 const N: usize,
363 P: Personality,
364 >(
365 target: FixedUInt<T, N, P>,
366 bits: u32,
367 ) -> FixedUInt<T, N, P> {
368 match P::TAG {
369 PersonalityTag::Nct => {
370 let (shift, overflow) =
371 normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
372 if overflow {
373 <FixedUInt<T, N, P> as ConstZero>::ZERO
374 } else {
375 target >> shift
376 }
377 }
378 PersonalityTag::Ct => {
379 let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
382 let capped = const_ct_min_u32(bits, bit_size_u32);
383 target >> (capped as usize)
384 }
385 }
386 }
387
388 c0nst fn const_ct_min_u32(bits: u32, cap: u32) -> u32 {
395 let diff = cap.wrapping_sub(bits);
397 let too_big_bit = (diff >> 31) & 1;
398 let too_big_mask = core::hint::black_box(too_big_bit.wrapping_neg());
399 bits ^ (too_big_mask & (bits ^ cap))
402 }
403
404 c0nst fn normalize_shift_amount(bits: u32, bit_size: usize) -> (usize, bool) {
407 let bit_size_u32 = bit_size as u32;
408 if bit_size == 0 {
409 (0, true)
411 } else if bit_size_u32 == 0 {
412 (bits as usize, false)
415 } else if bits >= bit_size_u32 {
416 ((bits % bit_size_u32) as usize, true)
418 } else {
419 (bits as usize, false)
420 }
421 }
422
423 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for FixedUInt<T, N, P> {
424 type Output = FixedUInt<T, N, P>;
425 fn overflowing_shl(self, bits: u32) -> (Self, bool) {
426 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
427 let res = core::ops::Shl::<usize>::shl(self, shift);
428 (res, overflow)
429 }
430 }
431
432 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
433 type Output = FixedUInt<T, N, P>;
434 fn overflowing_shr(self, bits: u32) -> (Self, bool) {
435 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
436 let res = core::ops::Shr::<usize>::shr(self, shift);
437 (res, overflow)
438 }
439 }
440
441 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for FixedUInt<T, N, P> {
442 type Output = FixedUInt<T, N, P>;
443 fn wrapping_shl(self, bits: u32) -> Self {
444 OverflowingShl::overflowing_shl(self, bits).0
445 }
446 }
447
448 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for FixedUInt<T, N, P> {
449 type Output = FixedUInt<T, N, P>;
450 fn wrapping_shr(self, bits: u32) -> Self {
451 OverflowingShr::overflowing_shr(self, bits).0
452 }
453 }
454
455 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for FixedUInt<T, N, P> {
456 type Output = FixedUInt<T, N, P>;
457 fn checked_shl(self, bits: u32) -> Option<Self> {
458 let (res, overflow) = OverflowingShl::overflowing_shl(self, bits);
459 if overflow { None } else { Some(res) }
460 }
461 }
462
463 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for FixedUInt<T, N, P> {
464 type Output = FixedUInt<T, N, P>;
465 fn checked_shr(self, bits: u32) -> Option<Self> {
466 let (res, overflow) = OverflowingShr::overflowing_shr(self, bits);
467 if overflow { None } else { Some(res) }
468 }
469 }
470
471 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for FixedUInt<T, N, P> {
472 type Output = FixedUInt<T, N, P>;
473 fn unbounded_shl(self, rhs: u32) -> Self {
474 const_unbounded_shl_u32(self, rhs)
475 }
476 }
477
478 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for FixedUInt<T, N, P> {
479 type Output = FixedUInt<T, N, P>;
480 fn unbounded_shr(self, rhs: u32) -> Self {
481 const_unbounded_shr_u32(self, rhs)
482 }
483 }
484
485 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for &FixedUInt<T, N, P> {
492 type Output = FixedUInt<T, N, P>;
493 fn overflowing_shl(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
494 <FixedUInt<T, N, P> as OverflowingShl>::overflowing_shl(FixedUInt::from_array(self.array), bits)
495 }
496 }
497
498 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for &FixedUInt<T, N, P> {
499 type Output = FixedUInt<T, N, P>;
500 fn overflowing_shr(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
501 <FixedUInt<T, N, P> as OverflowingShr>::overflowing_shr(FixedUInt::from_array(self.array), bits)
502 }
503 }
504
505 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for &FixedUInt<T, N, P> {
506 type Output = FixedUInt<T, N, P>;
507 fn wrapping_shl(self, bits: u32) -> FixedUInt<T, N, P> {
508 <FixedUInt<T, N, P> as WrappingShl>::wrapping_shl(FixedUInt::from_array(self.array), bits)
509 }
510 }
511
512 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for &FixedUInt<T, N, P> {
513 type Output = FixedUInt<T, N, P>;
514 fn wrapping_shr(self, bits: u32) -> FixedUInt<T, N, P> {
515 <FixedUInt<T, N, P> as WrappingShr>::wrapping_shr(FixedUInt::from_array(self.array), bits)
516 }
517 }
518
519 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for &FixedUInt<T, N, P> {
520 type Output = FixedUInt<T, N, P>;
521 fn checked_shl(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
522 <FixedUInt<T, N, P> as CheckedShl>::checked_shl(FixedUInt::from_array(self.array), bits)
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<FixedUInt<T, N, P>> {
529 <FixedUInt<T, N, P> as CheckedShr>::checked_shr(FixedUInt::from_array(self.array), bits)
530 }
531 }
532
533 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for &FixedUInt<T, N, P> {
534 type Output = FixedUInt<T, N, P>;
535 fn unbounded_shl(self, rhs: u32) -> FixedUInt<T, N, P> {
536 <FixedUInt<T, N, P> as UnboundedShl>::unbounded_shl(FixedUInt::from_array(self.array), rhs)
537 }
538 }
539
540 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for &FixedUInt<T, N, P> {
541 type Output = FixedUInt<T, N, P>;
542 fn unbounded_shr(self, rhs: u32) -> FixedUInt<T, N, P> {
543 <FixedUInt<T, N, P> as UnboundedShr>::unbounded_shr(FixedUInt::from_array(self.array), rhs)
544 }
545 }
546
547 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for FixedUInt<T, N, P> {
561 fn highest_one(self) -> Option<u32> {
562 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
563 if lz as usize == Self::BIT_SIZE {
564 None
565 } else {
566 Some(Self::BIT_SIZE as u32 - 1 - lz)
567 }
568 }
569 }
570
571 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for FixedUInt<T, N, P> {
572 fn lowest_one(self) -> Option<u32> {
573 let tz = <Self as const_num_traits::PrimBits>::trailing_zeros(self);
574 if tz as usize == Self::BIT_SIZE {
575 None
576 } else {
577 Some(tz)
578 }
579 }
580 }
581
582 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for &FixedUInt<T, N, P> {
583 fn highest_one(self) -> Option<u32> {
584 <FixedUInt<T, N, P> as const_num_traits::HighestOne>::highest_one(FixedUInt::from_array(self.array))
585 }
586 }
587
588 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for &FixedUInt<T, N, P> {
589 fn lowest_one(self) -> Option<u32> {
590 <FixedUInt<T, N, P> as const_num_traits::LowestOne>::lowest_one(FixedUInt::from_array(self.array))
591 }
592 }
593
594 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for FixedUInt<T, N, P> {
600 fn bit_width(self) -> u32 {
601 Self::BIT_SIZE as u32 - <Self as const_num_traits::PrimBits>::leading_zeros(self)
602 }
603 }
604
605 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for &FixedUInt<T, N, P> {
606 fn bit_width(self) -> u32 {
607 <FixedUInt<T, N, P> as const_num_traits::BitWidth>::bit_width(FixedUInt::from_array(self.array))
608 }
609 }
610
611 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitsPrecision for FixedUInt<T, N, P> {
618 fn bits_precision(&self) -> u32 {
619 Self::BIT_SIZE as u32
620 }
621 }
622
623 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitsPrecision for &FixedUInt<T, N, P> {
624 fn bits_precision(&self) -> u32 {
625 FixedUInt::<T, N, P>::BIT_SIZE as u32
626 }
627 }
628
629 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::WithPrecision for FixedUInt<T, N, P> {
635 fn widen_to_precision(self, _bits_precision: u32) -> Self {
636 self
637 }
638 }
639
640 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for FixedUInt<T, N, P> {
656 type Output = Self;
657 fn isolate_highest_one(self) -> Self {
658 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
659 if lz as usize == Self::BIT_SIZE {
660 <Self as const_num_traits::ConstZero>::ZERO
662 } else {
663 let pos = Self::BIT_SIZE as u32 - 1 - lz;
664 <Self as const_num_traits::ConstOne>::ONE << (pos as usize)
665 }
666 }
667 }
668
669 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for FixedUInt<T, N, P> {
670 type Output = Self;
671 fn isolate_lowest_one(self) -> Self {
672 let neg = <Self as const_num_traits::WrappingSub>::wrapping_sub(
675 <Self as const_num_traits::ConstZero>::ZERO,
676 self,
677 );
678 self & neg
679 }
680 }
681
682 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for &FixedUInt<T, N, P> {
683 type Output = FixedUInt<T, N, P>;
684 fn isolate_highest_one(self) -> FixedUInt<T, N, P> {
685 <FixedUInt<T, N, P> as const_num_traits::IsolateHighestOne>::isolate_highest_one(FixedUInt::from_array(self.array))
686 }
687 }
688
689 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for &FixedUInt<T, N, P> {
690 type Output = FixedUInt<T, N, P>;
691 fn isolate_lowest_one(self) -> FixedUInt<T, N, P> {
692 <FixedUInt<T, N, P> as const_num_traits::IsolateLowestOne>::isolate_lowest_one(FixedUInt::from_array(self.array))
693 }
694 }
695
696 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for FixedUInt<T, N, P> {
709 type Output = FixedUInt<T, N, P>;
710 fn shl_exact(self, rhs: u32) -> Option<Self> {
711 if (rhs as usize) < Self::BIT_SIZE
712 && rhs <= <Self as const_num_traits::PrimBits>::leading_zeros(self)
713 {
714 Some(self << (rhs as usize))
715 } else {
716 None
717 }
718 }
719 }
720
721 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for FixedUInt<T, N, P> {
722 type Output = FixedUInt<T, N, P>;
723 fn shr_exact(self, rhs: u32) -> Option<Self> {
724 if (rhs as usize) < Self::BIT_SIZE
725 && rhs <= <Self as const_num_traits::PrimBits>::trailing_zeros(self)
726 {
727 Some(self >> (rhs as usize))
728 } else {
729 None
730 }
731 }
732 }
733
734 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for &FixedUInt<T, N, P> {
735 type Output = FixedUInt<T, N, P>;
736 fn shl_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
737 <FixedUInt<T, N, P> as const_num_traits::ShlExact>::shl_exact(FixedUInt::from_array(self.array), rhs)
738 }
739 }
740
741 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for &FixedUInt<T, N, P> {
742 type Output = FixedUInt<T, N, P>;
743 fn shr_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
744 <FixedUInt<T, N, P> as const_num_traits::ShrExact>::shr_exact(FixedUInt::from_array(self.array), rhs)
745 }
746 }
747
748 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for FixedUInt<T, N, P> {
758 type Output = Self;
759 fn funnel_shl(self, rhs: Self, n: u32) -> Self {
760 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shl: n out of range");
761 if n == 0 {
762 self
763 } else {
764 let lo_shift = Self::BIT_SIZE as u32 - n;
765 (self << (n as usize)) | (rhs >> (lo_shift as usize))
766 }
767 }
768 }
769
770 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for FixedUInt<T, N, P> {
771 type Output = Self;
772 fn funnel_shr(self, rhs: Self, n: u32) -> Self {
773 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shr: n out of range");
774 if n == 0 {
775 rhs
776 } else {
777 let hi_shift = Self::BIT_SIZE as u32 - n;
778 (rhs >> (n as usize)) | (self << (hi_shift as usize))
779 }
780 }
781 }
782
783 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for &FixedUInt<T, N, P> {
784 type Output = FixedUInt<T, N, P>;
785 fn funnel_shl(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
786 <FixedUInt<T, N, P> as const_num_traits::FunnelShl>::funnel_shl(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
787 }
788 }
789
790 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for &FixedUInt<T, N, P> {
791 type Output = FixedUInt<T, N, P>;
792 fn funnel_shr(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
793 <FixedUInt<T, N, P> as const_num_traits::FunnelShr>::funnel_shr(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
794 }
795 }
796
797 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for FixedUInt<T, N, Nct> {
807 type Output = Self;
808 fn deposit_bits(self, mask: Self) -> Self {
809 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
812 let mut remaining = mask;
813 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
814 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
815 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
817 if !<Self as const_num_traits::Zero>::is_zero(&(self & bb)) {
818 result |= lowest;
819 }
820 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
821 remaining,
822 <Self as const_num_traits::ConstOne>::ONE,
823 );
824 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
825 }
826 result
827 }
828 }
829
830 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for FixedUInt<T, N, Nct> {
831 type Output = Self;
832 fn extract_bits(self, mask: Self) -> Self {
833 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
836 let mut remaining = mask;
837 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
838 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
839 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
840 if !<Self as const_num_traits::Zero>::is_zero(&(self & lowest)) {
841 result |= bb;
842 }
843 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
844 remaining,
845 <Self as const_num_traits::ConstOne>::ONE,
846 );
847 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
848 }
849 result
850 }
851 }
852
853 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for &FixedUInt<T, N, Nct> {
854 type Output = FixedUInt<T, N, Nct>;
855 fn deposit_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
856 <FixedUInt<T, N, Nct> as const_num_traits::DepositBits>::deposit_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
857 }
858 }
859
860 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for &FixedUInt<T, N, Nct> {
861 type Output = FixedUInt<T, N, Nct>;
862 fn extract_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
863 <FixedUInt<T, N, Nct> as const_num_traits::ExtractBits>::extract_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
864 }
865 }
866}
867
868#[cfg(feature = "num-traits")]
870impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
871 for FixedUInt<T, N, P>
872{
873 fn wrapping_shl(&self, bits: u32) -> Self {
874 <&Self as WrappingShl>::wrapping_shl(self, bits)
875 }
876}
877
878#[cfg(feature = "num-traits")]
879impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
880 for FixedUInt<T, N, P>
881{
882 fn wrapping_shr(&self, bits: u32) -> Self {
883 <&Self as WrappingShr>::wrapping_shr(self, bits)
884 }
885}
886
887#[cfg(feature = "num-traits")]
888impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
889 fn checked_shl(&self, bits: u32) -> Option<Self> {
890 <&Self as CheckedShl>::checked_shl(self, bits)
891 }
892}
893
894#[cfg(feature = "num-traits")]
895impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
896 fn checked_shr(&self, bits: u32) -> Option<Self> {
897 <&Self as CheckedShr>::checked_shr(self, bits)
898 }
899}
900
901#[cfg(test)]
902#[allow(clippy::op_ref)]
905mod tests {
906 use super::*;
907
908 #[test]
909 fn test_bitand_combinations() {
910 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);
916 assert_eq!(a & &b, expected);
918 assert_eq!(&a & b, expected);
920 assert_eq!(&a & &b, expected);
922 }
923
924 #[test]
925 fn test_bitor_combinations() {
926 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);
932 assert_eq!(a | &b, expected);
934 assert_eq!(&a | b, expected);
936 assert_eq!(&a | &b, expected);
938 }
939
940 #[test]
941 fn test_bitxor_combinations() {
942 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);
948 assert_eq!(a ^ &b, expected);
950 assert_eq!(&a ^ b, expected);
952 assert_eq!(&a ^ &b, expected);
954 }
955
956 #[test]
957 fn test_shl_combinations() {
958 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
960 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
964 assert_eq!(a << &shift, expected);
966 assert_eq!(&a << shift, expected);
968 assert_eq!(&a << &shift, expected);
970
971 let shift32: u32 = 2;
973 assert_eq!(a << shift32, expected);
974 assert_eq!(a << &shift32, expected);
975 assert_eq!(&a << shift32, expected);
976 assert_eq!(&a << &shift32, expected);
977 }
978
979 #[test]
980 fn test_shr_combinations() {
981 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
983 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
987 assert_eq!(a >> &shift, expected);
989 assert_eq!(&a >> shift, expected);
991 assert_eq!(&a >> &shift, expected);
993
994 let shift32: u32 = 2;
996 assert_eq!(a >> shift32, expected);
997 assert_eq!(a >> &shift32, expected);
998 assert_eq!(&a >> shift32, expected);
999 assert_eq!(&a >> &shift32, expected);
1000 }
1001
1002 #[test]
1003 fn test_const_bitops() {
1004 type TestInt = FixedUInt<u8, 2>;
1005
1006 let a = TestInt::from(0b11001100u8);
1007 let b = TestInt::from(0b10101010u8);
1008
1009 let not_a = !a;
1011 assert_eq!(not_a.array[0], 0b00110011);
1012 assert_eq!(not_a.array[1], 0xFF);
1013
1014 assert_eq!(a & b, TestInt::from(0b10001000u8));
1016
1017 assert_eq!(a | b, TestInt::from(0b11101110u8));
1019
1020 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
1022
1023 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
1025
1026 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
1028
1029 #[cfg(feature = "nightly")]
1030 {
1031 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
1032 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
1033
1034 const NOT_A: TestInt = !A;
1035 const AND_AB: TestInt = A & B;
1036 const OR_AB: TestInt = A | B;
1037 const XOR_AB: TestInt = A ^ B;
1038 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
1039 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
1040
1041 assert_eq!(NOT_A.array[0], 0b00110011);
1042 assert_eq!(AND_AB.array[0], 0b10001000);
1043 assert_eq!(OR_AB.array[0], 0b11101110);
1044 assert_eq!(XOR_AB.array[0], 0b01100110);
1045 assert_eq!(SHL_1.array[0], 16);
1046 assert_eq!(SHR_16.array[0], 4);
1047 }
1048 }
1049
1050 #[test]
1051 fn test_const_shift_traits() {
1052 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = OverflowingShl::overflowing_shl(a, 8);
1057 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
1059
1060 let (res, overflow) = OverflowingShl::overflowing_shl(a, 16);
1061 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
1063
1064 let (res, overflow) = OverflowingShl::overflowing_shl(a, 9);
1065 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = OverflowingShr::overflowing_shr(b, 8);
1071 assert_eq!(res.array, [1, 0]); assert!(!overflow);
1073
1074 let (res, overflow) = OverflowingShr::overflowing_shr(b, 16);
1075 assert_eq!(res.array, [0, 1]); assert!(overflow);
1077
1078 let c = TestInt::from(1u8);
1080 assert_eq!(WrappingShl::wrapping_shl(c, 4).array, [16, 0]);
1081 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);
1086 assert_eq!(WrappingShr::wrapping_shr(d, 4).array, [0, 0x08]);
1087 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);
1092 assert_eq!(CheckedShl::checked_shl(e, 4), Some(TestInt::from(16u8)));
1093 assert_eq!(
1094 CheckedShl::checked_shl(e, 15),
1095 Some(TestInt::from(0x8000u16))
1096 );
1097 assert_eq!(CheckedShl::checked_shl(e, 16), None); let f = TestInt::from(0x8000u16);
1101 assert_eq!(CheckedShr::checked_shr(f, 15), Some(TestInt::from(1u8)));
1102 assert_eq!(CheckedShr::checked_shr(f, 16), None); let g = TestInt::from(42u8);
1106 assert_eq!(OverflowingShl::overflowing_shl(g, 0), (g, false));
1107 assert_eq!(OverflowingShr::overflowing_shr(g, 0), (g, false));
1108 assert_eq!(WrappingShl::wrapping_shl(g, 0), g);
1109 assert_eq!(WrappingShr::wrapping_shr(g, 0), g);
1110 assert_eq!(CheckedShl::checked_shl(g, 0), Some(g));
1111 assert_eq!(CheckedShr::checked_shr(g, 0), Some(g));
1112 }
1113
1114 #[test]
1115 fn test_const_shift_traits_n0() {
1116 type ZeroInt = FixedUInt<u8, 0>;
1118 let z = ZeroInt::from_array([]);
1119
1120 assert_eq!(OverflowingShl::overflowing_shl(z, 0), (z, true));
1122 assert_eq!(OverflowingShr::overflowing_shr(z, 0), (z, true));
1123 assert_eq!(WrappingShl::wrapping_shl(z, 0), z);
1124 assert_eq!(WrappingShr::wrapping_shr(z, 0), z);
1125 assert_eq!(CheckedShl::checked_shl(z, 0), None);
1126 assert_eq!(CheckedShr::checked_shr(z, 0), None);
1127 }
1128
1129 #[test]
1130 #[cfg(feature = "num-traits")]
1131 fn test_num_traits_shift_wrappers() {
1132 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
1133
1134 type TestInt = FixedUInt<u8, 2>;
1135
1136 let a = TestInt::from(1u8);
1137
1138 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
1140 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
1144 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
1145
1146 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
1148 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
1149
1150 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
1152 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
1153 }
1154
1155 #[test]
1156 fn test_unbounded_shift() {
1157 type U16 = FixedUInt<u8, 2>;
1158
1159 let one = U16::from(1u8);
1160
1161 assert_eq!(UnboundedShl::unbounded_shl(one, 0), one);
1163 assert_eq!(UnboundedShl::unbounded_shl(one, 4), U16::from(16u8));
1164 assert_eq!(UnboundedShl::unbounded_shl(one, 15), U16::from(0x8000u16));
1165
1166 assert_eq!(UnboundedShr::unbounded_shr(U16::from(0x8000u16), 15), one);
1167 assert_eq!(UnboundedShr::unbounded_shr(U16::from(16u8), 4), one);
1168
1169 assert_eq!(UnboundedShl::unbounded_shl(one, 16), U16::from(0u8));
1171 assert_eq!(
1172 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 16),
1173 U16::from(0u8)
1174 );
1175
1176 assert_eq!(
1178 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 17),
1179 U16::from(0u8)
1180 );
1181 assert_eq!(
1182 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 100),
1183 U16::from(0u8)
1184 );
1185 assert_eq!(
1186 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 17),
1187 U16::from(0u8)
1188 );
1189 assert_eq!(
1190 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 100),
1191 U16::from(0u8)
1192 );
1193
1194 type U32 = FixedUInt<u8, 4>;
1196 let one32 = U32::from(1u8);
1197 assert_eq!(
1198 UnboundedShl::unbounded_shl(one32, 31),
1199 U32::from(0x80000000u32)
1200 );
1201 assert_eq!(UnboundedShl::unbounded_shl(one32, 32), U32::from(0u8));
1202 assert_eq!(
1203 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 31),
1204 one32
1205 );
1206 assert_eq!(
1207 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 32),
1208 U32::from(0u8)
1209 );
1210 }
1211
1212 #[test]
1213 fn test_unbounded_shift_polymorphic() {
1214 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
1215 where
1216 T: UnboundedShl<Output = T> + UnboundedShr<Output = T> + Eq + core::fmt::Debug + Copy,
1217 {
1218 assert_eq!(UnboundedShl::unbounded_shl(val, shift), expected_shl);
1219 assert_eq!(UnboundedShr::unbounded_shr(val, shift), expected_shr);
1220 }
1221
1222 type U8x2 = FixedUInt<u8, 2>;
1224 type U8x4 = FixedUInt<u8, 4>;
1225 type U16x2 = FixedUInt<u16, 2>;
1226
1227 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
1229 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
1230 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
1231
1232 test_unbounded(1u8, 4, 16u8, 0u8);
1234 test_unbounded(1u16, 4, 16u16, 0u16);
1235 test_unbounded(1u32, 4, 16u32, 0u32);
1236
1237 test_unbounded(1u8, 8, 0u8, 0u8);
1239 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
1240 }
1241
1242 #[test]
1243 fn test_bit_width() {
1244 use const_num_traits::BitWidth;
1245 type U16 = FixedUInt<u8, 2>;
1246 assert_eq!(BitWidth::bit_width(U16::from(0u8)), 0);
1247 assert_eq!(BitWidth::bit_width(U16::from(1u8)), 1);
1248 assert_eq!(BitWidth::bit_width(U16::from(2u8)), 2);
1249 assert_eq!(BitWidth::bit_width(U16::from(3u8)), 2);
1250 assert_eq!(BitWidth::bit_width(U16::from(255u8)), 8);
1251 assert_eq!(BitWidth::bit_width(U16::from(256u16)), 9);
1252 assert_eq!(BitWidth::bit_width(U16::from(0xFFFFu16)), 16);
1253 }
1254
1255 #[test]
1256 fn test_bits_precision() {
1257 use const_num_traits::BitsPrecision;
1258 type U16 = FixedUInt<u8, 2>;
1260 type U32 = FixedUInt<u32, 1>;
1261 assert_eq!(BitsPrecision::bits_precision(&U16::from(0u8)), 16);
1262 assert_eq!(BitsPrecision::bits_precision(&U16::from(0xFFFFu16)), 16);
1263 assert_eq!(BitsPrecision::bits_precision(&U32::from(0u8)), 32);
1264 assert_eq!(BitsPrecision::bits_precision(&U32::from(7u8)), 32);
1265 }
1266
1267 #[test]
1268 fn test_highest_lowest_one() {
1269 use const_num_traits::{HighestOne, LowestOne};
1270 type U16 = FixedUInt<u8, 2>;
1271 assert_eq!(HighestOne::highest_one(U16::from(0u8)), None);
1272 assert_eq!(HighestOne::highest_one(U16::from(1u8)), Some(0));
1273 assert_eq!(HighestOne::highest_one(U16::from(0b1010_0000u8)), Some(7));
1274 assert_eq!(HighestOne::highest_one(U16::from(0x8000u16)), Some(15));
1275
1276 assert_eq!(LowestOne::lowest_one(U16::from(0u8)), None);
1277 assert_eq!(LowestOne::lowest_one(U16::from(1u8)), Some(0));
1278 assert_eq!(LowestOne::lowest_one(U16::from(0b0010_1000u8)), Some(3));
1279 assert_eq!(LowestOne::lowest_one(U16::from(0x8000u16)), Some(15));
1280 }
1281
1282 #[test]
1283 fn test_isolate_highest_lowest_one() {
1284 use const_num_traits::{IsolateHighestOne, IsolateLowestOne};
1285 type U16 = FixedUInt<u8, 2>;
1286 assert_eq!(
1288 IsolateHighestOne::isolate_highest_one(U16::from(0u8)),
1289 U16::from(0u8)
1290 );
1291 assert_eq!(
1292 IsolateLowestOne::isolate_lowest_one(U16::from(0u8)),
1293 U16::from(0u8)
1294 );
1295 assert_eq!(
1297 IsolateHighestOne::isolate_highest_one(U16::from(0b1010_0000u8)),
1298 U16::from(0b1000_0000u8)
1299 );
1300 assert_eq!(
1301 IsolateLowestOne::isolate_lowest_one(U16::from(0b1010_1000u8)),
1302 U16::from(0b0000_1000u8)
1303 );
1304 let p: U16 = U16::from(0x0100u16);
1306 assert_eq!(IsolateHighestOne::isolate_highest_one(p), p);
1307 assert_eq!(IsolateLowestOne::isolate_lowest_one(p), p);
1308 }
1309
1310 #[test]
1311 fn test_shl_shr_exact() {
1312 use const_num_traits::{ShlExact, ShrExact};
1313 type U16 = FixedUInt<u8, 2>;
1314 assert_eq!(
1316 ShlExact::shl_exact(U16::from(1u8), 4),
1317 Some(U16::from(16u8))
1318 );
1319 assert_eq!(ShlExact::shl_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1320 assert_eq!(ShlExact::shl_exact(U16::from(0x8000u16), 1), None);
1322 assert_eq!(ShlExact::shl_exact(U16::from(1u8), 16), None);
1324
1325 assert_eq!(
1327 ShrExact::shr_exact(U16::from(16u8), 4),
1328 Some(U16::from(1u8))
1329 );
1330 assert_eq!(ShrExact::shr_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1331 assert_eq!(ShrExact::shr_exact(U16::from(0b0001u8), 1), None);
1333 assert_eq!(ShrExact::shr_exact(U16::from(0b0011u8), 1), None);
1334 assert_eq!(ShrExact::shr_exact(U16::from(1u8), 16), None);
1336 }
1337
1338 #[test]
1339 #[allow(clippy::needless_borrows_for_generic_args)]
1340 fn test_ref_receivers_compile_through() {
1341 use const_num_traits::{BitWidth, IsolateHighestOne, IsolateLowestOne, ShlExact, ShrExact};
1342 type U16 = FixedUInt<u8, 2>;
1343 let v = U16::from(0b0010_1000u8);
1344 assert_eq!(BitWidth::bit_width(&v), 6);
1345 assert_eq!(
1346 IsolateHighestOne::isolate_highest_one(&v),
1347 U16::from(0b0010_0000u8)
1348 );
1349 assert_eq!(
1350 IsolateLowestOne::isolate_lowest_one(&v),
1351 U16::from(0b0000_1000u8)
1352 );
1353 assert_eq!(ShlExact::shl_exact(&v, 2), Some(U16::from(0b1010_0000u8)));
1354 assert_eq!(ShrExact::shr_exact(&v, 3), Some(U16::from(0b0000_0101u8)));
1355 }
1356
1357 #[test]
1358 fn test_funnel_shifts() {
1359 use const_num_traits::{FunnelShl, FunnelShr};
1360 type U16 = FixedUInt<u8, 2>;
1361
1362 assert_eq!(
1364 FunnelShl::funnel_shl(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1365 U16::from(0x0003u16),
1366 );
1367 assert_eq!(
1369 FunnelShl::funnel_shl(U16::from(0xABCDu16), U16::from(0xFFFFu16), 0),
1370 U16::from(0xABCDu16),
1371 );
1372 assert_eq!(
1374 FunnelShr::funnel_shr(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1375 U16::from(0xC000u16),
1376 );
1377 assert_eq!(
1379 FunnelShr::funnel_shr(U16::from(0xABCDu16), U16::from(0x1234u16), 0),
1380 U16::from(0x1234u16),
1381 );
1382
1383 let hi = U16::from(0x0001u16);
1385 let lo = U16::from(0x8000u16);
1386 assert_eq!(FunnelShl::funnel_shl(&hi, &lo, 1), U16::from(0x0003u16));
1387 assert_eq!(FunnelShr::funnel_shr(&hi, &lo, 1), U16::from(0xC000u16));
1388 }
1389
1390 #[test]
1391 #[should_panic(expected = "funnel_shl: n out of range")]
1392 fn test_funnel_shl_panics_at_bit_size() {
1393 use const_num_traits::FunnelShl;
1394 type U16 = FixedUInt<u8, 2>;
1395 let _ = FunnelShl::funnel_shl(U16::from(1u8), U16::from(0u8), 16);
1396 }
1397
1398 #[test]
1399 fn test_deposit_extract_bits() {
1400 use const_num_traits::Nct;
1401 use const_num_traits::{DepositBits, ExtractBits};
1402 type U16 = FixedUInt<u8, 2, Nct>;
1403
1404 assert_eq!(
1407 DepositBits::deposit_bits(U16::from(0b101u8), U16::from(0b1111_0000u8)),
1408 U16::from(0b0101_0000u8),
1409 );
1410 assert_eq!(
1412 ExtractBits::extract_bits(U16::from(0b0101_0011u8), U16::from(0b1111_0000u8)),
1413 U16::from(0b101u8),
1414 );
1415
1416 assert_eq!(
1418 DepositBits::deposit_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1419 U16::from(0u8),
1420 );
1421 assert_eq!(
1422 ExtractBits::extract_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1423 U16::from(0u8),
1424 );
1425
1426 assert_eq!(
1428 DepositBits::deposit_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1429 U16::from(0xABCDu16),
1430 );
1431 assert_eq!(
1432 ExtractBits::extract_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1433 U16::from(0xABCDu16),
1434 );
1435
1436 let mask = U16::from(0b1010_1010u8);
1440 let v = U16::from(0b1111_1111u8);
1441 let extracted = ExtractBits::extract_bits(v, mask);
1442 let redeposited = DepositBits::deposit_bits(extracted, mask);
1443 assert_eq!(redeposited, v & mask);
1444
1445 let v_ref = U16::from(0b0110_0110u8);
1447 let m_ref = U16::from(0b1111_0000u8);
1448 assert_eq!(
1449 ExtractBits::extract_bits(&v_ref, &m_ref),
1450 U16::from(0b0110u8),
1451 );
1452 assert_eq!(
1453 DepositBits::deposit_bits(&U16::from(0b101u8), &m_ref),
1454 U16::from(0b0101_0000u8),
1455 );
1456 }
1457
1458 c0nst::c0nst! {
1468 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) {
1469 OverflowingShl::overflowing_shl(v, bits)
1470 }
1471 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) {
1472 OverflowingShr::overflowing_shr(v, bits)
1473 }
1474 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> {
1475 WrappingShl::wrapping_shl(v, bits)
1476 }
1477 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> {
1478 WrappingShr::wrapping_shr(v, bits)
1479 }
1480 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>> {
1481 CheckedShl::checked_shl(v, bits)
1482 }
1483 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>> {
1484 CheckedShr::checked_shr(v, bits)
1485 }
1486 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> {
1487 UnboundedShl::unbounded_shl(v, bits)
1488 }
1489 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> {
1490 UnboundedShr::unbounded_shr(v, bits)
1491 }
1492 pub c0nst fn const_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1493 const_num_traits::HighestOne::highest_one(v)
1494 }
1495 pub c0nst fn const_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1496 const_num_traits::LowestOne::lowest_one(v)
1497 }
1498 pub c0nst fn const_bit_width<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
1499 const_num_traits::BitWidth::bit_width(v)
1500 }
1501 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> {
1502 const_num_traits::IsolateHighestOne::isolate_highest_one(v)
1503 }
1504 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> {
1505 const_num_traits::IsolateLowestOne::isolate_lowest_one(v)
1506 }
1507 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>> {
1508 const_num_traits::ShlExact::shl_exact(v, bits)
1509 }
1510 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>> {
1511 const_num_traits::ShrExact::shr_exact(v, bits)
1512 }
1513 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> {
1514 const_num_traits::FunnelShl::funnel_shl(hi, lo, n)
1515 }
1516 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> {
1517 const_num_traits::FunnelShr::funnel_shr(hi, lo, n)
1518 }
1519 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> {
1520 const_num_traits::DepositBits::deposit_bits(v, mask)
1521 }
1522 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> {
1523 const_num_traits::ExtractBits::extract_bits(v, mask)
1524 }
1525 }
1526
1527 #[test]
1528 fn nightly_const_eval_bit_traits() {
1529 type U16 = FixedUInt<u8, 2>;
1530
1531 let v = U16::from(1u8);
1533 assert_eq!(const_overflowing_shl(v, 4), (U16::from(16u8), false));
1534 assert_eq!(const_wrapping_shl(v, 4), U16::from(16u8));
1535 assert_eq!(const_checked_shl(v, 16), None);
1536 assert_eq!(const_bit_width(U16::from(0xFFu8)), 8);
1537
1538 #[cfg(feature = "nightly")]
1540 {
1541 const V: U16 = FixedUInt::from_array([1, 0]);
1542 const V_FF: U16 = FixedUInt::from_array([0xFF, 0]);
1543 const V_MASK: U16 = FixedUInt::from_array([0b1010_1000, 0]);
1544 const HI: U16 = FixedUInt::from_array([1, 0]);
1545 const LO: U16 = FixedUInt::from_array([0, 0x80]);
1546
1547 const OSHL: (U16, bool) = const_overflowing_shl(V, 4);
1548 const OSHR: (U16, bool) = const_overflowing_shr(V_FF, 4);
1549 const WSHL: U16 = const_wrapping_shl(V, 4);
1550 const WSHR: U16 = const_wrapping_shr(V_FF, 4);
1551 const CSHL: Option<U16> = const_checked_shl(V, 16);
1552 const CSHR: Option<U16> = const_checked_shr(V, 4);
1553 const USHL: U16 = const_unbounded_shl(V, 8);
1554 const USHR: U16 = const_unbounded_shr(V_FF, 4);
1555 const HI_ONE: Option<u32> = const_highest_one(V_FF);
1556 const LO_ONE: Option<u32> = const_lowest_one(V_MASK);
1557 const BW: u32 = const_bit_width(V_FF);
1558 const IH: U16 = const_isolate_highest_one(V_MASK);
1559 const IL: U16 = const_isolate_lowest_one(V_MASK);
1560 const SHLEX: Option<U16> = const_shl_exact(V, 4);
1561 const SHREX: Option<U16> = const_shr_exact(FixedUInt::from_array([16, 0]), 4);
1562 const FSHL: U16 = const_funnel_shl(HI, LO, 1);
1563 const FSHR: U16 = const_funnel_shr(HI, LO, 1);
1564 const DEP: U16 = const_deposit_bits(
1565 FixedUInt::from_array([0b101, 0]),
1566 FixedUInt::from_array([0b1111_0000, 0]),
1567 );
1568 const EXT: U16 = const_extract_bits(
1569 FixedUInt::from_array([0b0101_0011, 0]),
1570 FixedUInt::from_array([0b1111_0000, 0]),
1571 );
1572
1573 assert_eq!(OSHL.0.array, [16, 0]);
1575 assert!(!OSHL.1);
1576 assert_eq!(OSHR.0.array, [0x0F, 0]);
1577 assert!(!OSHR.1);
1578 assert_eq!(WSHL.array, [16, 0]);
1579 assert_eq!(WSHR.array, [0x0F, 0]);
1580 assert!(CSHL.is_none());
1581 assert!(CSHR.is_some());
1582 assert_eq!(USHL.array, [0, 1]);
1583 assert_eq!(USHR.array, [0x0F, 0]);
1584 assert_eq!(HI_ONE, Some(7));
1585 assert_eq!(LO_ONE, Some(3));
1586 assert_eq!(BW, 8);
1587 assert_eq!(IH.array, [0b1000_0000, 0]);
1588 assert_eq!(IL.array, [0b0000_1000, 0]);
1589 assert!(SHLEX.is_some());
1590 assert!(SHREX.is_some());
1591 assert_eq!(FSHL.array, [0x03, 0]);
1592 assert_eq!(FSHR.array, [0x00, 0xC0]);
1593 assert_eq!(DEP.array, [0b0101_0000, 0]);
1594 assert_eq!(EXT.array, [0b101, 0]);
1595 }
1596 }
1597}