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 (*self).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 (*self).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 (*self).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 (*self).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 (*self).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 (*self).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 (*self).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 (*self).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 fn overflowing_shl(self, bits: u32) -> (Self, bool) {
425 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
426 let res = core::ops::Shl::<usize>::shl(self, shift);
427 (res, overflow)
428 }
429 }
430
431 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
432 fn overflowing_shr(self, bits: u32) -> (Self, bool) {
433 let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
434 let res = core::ops::Shr::<usize>::shr(self, shift);
435 (res, overflow)
436 }
437 }
438
439 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for FixedUInt<T, N, P> {
440 fn wrapping_shl(self, bits: u32) -> Self {
441 OverflowingShl::overflowing_shl(self, bits).0
442 }
443 }
444
445 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for FixedUInt<T, N, P> {
446 fn wrapping_shr(self, bits: u32) -> Self {
447 OverflowingShr::overflowing_shr(self, bits).0
448 }
449 }
450
451 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for FixedUInt<T, N, P> {
452 fn checked_shl(self, bits: u32) -> Option<Self> {
453 let (res, overflow) = OverflowingShl::overflowing_shl(self, bits);
454 if overflow { None } else { Some(res) }
455 }
456 }
457
458 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for FixedUInt<T, N, P> {
459 fn checked_shr(self, bits: u32) -> Option<Self> {
460 let (res, overflow) = OverflowingShr::overflowing_shr(self, bits);
461 if overflow { None } else { Some(res) }
462 }
463 }
464
465 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for FixedUInt<T, N, P> {
466 fn unbounded_shl(self, rhs: u32) -> Self {
467 const_unbounded_shl_u32(self, rhs)
468 }
469 }
470
471 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for FixedUInt<T, N, P> {
472 fn unbounded_shr(self, rhs: u32) -> Self {
473 const_unbounded_shr_u32(self, rhs)
474 }
475 }
476
477 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for &FixedUInt<T, N, P> {
484 fn overflowing_shl(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
485 <FixedUInt<T, N, P> as OverflowingShl>::overflowing_shl(*self, bits)
486 }
487 }
488
489 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for &FixedUInt<T, N, P> {
490 fn overflowing_shr(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
491 <FixedUInt<T, N, P> as OverflowingShr>::overflowing_shr(*self, bits)
492 }
493 }
494
495 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for &FixedUInt<T, N, P> {
496 fn wrapping_shl(self, bits: u32) -> FixedUInt<T, N, P> {
497 <FixedUInt<T, N, P> as WrappingShl>::wrapping_shl(*self, bits)
498 }
499 }
500
501 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for &FixedUInt<T, N, P> {
502 fn wrapping_shr(self, bits: u32) -> FixedUInt<T, N, P> {
503 <FixedUInt<T, N, P> as WrappingShr>::wrapping_shr(*self, bits)
504 }
505 }
506
507 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for &FixedUInt<T, N, P> {
508 fn checked_shl(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
509 <FixedUInt<T, N, P> as CheckedShl>::checked_shl(*self, bits)
510 }
511 }
512
513 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for &FixedUInt<T, N, P> {
514 fn checked_shr(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
515 <FixedUInt<T, N, P> as CheckedShr>::checked_shr(*self, bits)
516 }
517 }
518
519 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for &FixedUInt<T, N, P> {
520 fn unbounded_shl(self, rhs: u32) -> FixedUInt<T, N, P> {
521 <FixedUInt<T, N, P> as UnboundedShl>::unbounded_shl(*self, rhs)
522 }
523 }
524
525 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for &FixedUInt<T, N, P> {
526 fn unbounded_shr(self, rhs: u32) -> FixedUInt<T, N, P> {
527 <FixedUInt<T, N, P> as UnboundedShr>::unbounded_shr(*self, rhs)
528 }
529 }
530
531 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for FixedUInt<T, N, P> {
545 fn highest_one(self) -> Option<u32> {
546 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
547 if lz as usize == Self::BIT_SIZE {
548 None
549 } else {
550 Some(Self::BIT_SIZE as u32 - 1 - lz)
551 }
552 }
553 }
554
555 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for FixedUInt<T, N, P> {
556 fn lowest_one(self) -> Option<u32> {
557 let tz = <Self as const_num_traits::PrimBits>::trailing_zeros(self);
558 if tz as usize == Self::BIT_SIZE {
559 None
560 } else {
561 Some(tz)
562 }
563 }
564 }
565
566 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for &FixedUInt<T, N, P> {
567 fn highest_one(self) -> Option<u32> {
568 <FixedUInt<T, N, P> as const_num_traits::HighestOne>::highest_one(*self)
569 }
570 }
571
572 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for &FixedUInt<T, N, P> {
573 fn lowest_one(self) -> Option<u32> {
574 <FixedUInt<T, N, P> as const_num_traits::LowestOne>::lowest_one(*self)
575 }
576 }
577
578 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for FixedUInt<T, N, P> {
584 fn bit_width(self) -> u32 {
585 Self::BIT_SIZE as u32 - <Self as const_num_traits::PrimBits>::leading_zeros(self)
586 }
587 }
588
589 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for &FixedUInt<T, N, P> {
590 fn bit_width(self) -> u32 {
591 <FixedUInt<T, N, P> as const_num_traits::BitWidth>::bit_width(*self)
592 }
593 }
594
595 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for FixedUInt<T, N, P> {
611 type Output = Self;
612 fn isolate_highest_one(self) -> Self {
613 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
614 if lz as usize == Self::BIT_SIZE {
615 <Self as const_num_traits::ConstZero>::ZERO
617 } else {
618 let pos = Self::BIT_SIZE as u32 - 1 - lz;
619 <Self as const_num_traits::ConstOne>::ONE << (pos as usize)
620 }
621 }
622 }
623
624 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for FixedUInt<T, N, P> {
625 type Output = Self;
626 fn isolate_lowest_one(self) -> Self {
627 let neg = <Self as const_num_traits::WrappingSub>::wrapping_sub(
630 <Self as const_num_traits::ConstZero>::ZERO,
631 self,
632 );
633 self & neg
634 }
635 }
636
637 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for &FixedUInt<T, N, P> {
638 type Output = FixedUInt<T, N, P>;
639 fn isolate_highest_one(self) -> FixedUInt<T, N, P> {
640 <FixedUInt<T, N, P> as const_num_traits::IsolateHighestOne>::isolate_highest_one(*self)
641 }
642 }
643
644 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for &FixedUInt<T, N, P> {
645 type Output = FixedUInt<T, N, P>;
646 fn isolate_lowest_one(self) -> FixedUInt<T, N, P> {
647 <FixedUInt<T, N, P> as const_num_traits::IsolateLowestOne>::isolate_lowest_one(*self)
648 }
649 }
650
651 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for FixedUInt<T, N, P> {
664 fn shl_exact(self, rhs: u32) -> Option<Self> {
665 if (rhs as usize) < Self::BIT_SIZE
666 && rhs <= <Self as const_num_traits::PrimBits>::leading_zeros(self)
667 {
668 Some(self << (rhs as usize))
669 } else {
670 None
671 }
672 }
673 }
674
675 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for FixedUInt<T, N, P> {
676 fn shr_exact(self, rhs: u32) -> Option<Self> {
677 if (rhs as usize) < Self::BIT_SIZE
678 && rhs <= <Self as const_num_traits::PrimBits>::trailing_zeros(self)
679 {
680 Some(self >> (rhs as usize))
681 } else {
682 None
683 }
684 }
685 }
686
687 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for &FixedUInt<T, N, P> {
688 fn shl_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
689 <FixedUInt<T, N, P> as const_num_traits::ShlExact>::shl_exact(*self, rhs)
690 }
691 }
692
693 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for &FixedUInt<T, N, P> {
694 fn shr_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
695 <FixedUInt<T, N, P> as const_num_traits::ShrExact>::shr_exact(*self, rhs)
696 }
697 }
698
699 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for FixedUInt<T, N, P> {
709 type Output = Self;
710 fn funnel_shl(self, rhs: Self, n: u32) -> Self {
711 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shl: n out of range");
712 if n == 0 {
713 self
714 } else {
715 let lo_shift = Self::BIT_SIZE as u32 - n;
716 (self << (n as usize)) | (rhs >> (lo_shift as usize))
717 }
718 }
719 }
720
721 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for FixedUInt<T, N, P> {
722 type Output = Self;
723 fn funnel_shr(self, rhs: Self, n: u32) -> Self {
724 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shr: n out of range");
725 if n == 0 {
726 rhs
727 } else {
728 let hi_shift = Self::BIT_SIZE as u32 - n;
729 (rhs >> (n as usize)) | (self << (hi_shift as usize))
730 }
731 }
732 }
733
734 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for &FixedUInt<T, N, P> {
735 type Output = FixedUInt<T, N, P>;
736 fn funnel_shl(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
737 <FixedUInt<T, N, P> as const_num_traits::FunnelShl>::funnel_shl(*self, *rhs, n)
738 }
739 }
740
741 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for &FixedUInt<T, N, P> {
742 type Output = FixedUInt<T, N, P>;
743 fn funnel_shr(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
744 <FixedUInt<T, N, P> as const_num_traits::FunnelShr>::funnel_shr(*self, *rhs, n)
745 }
746 }
747
748 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for FixedUInt<T, N, Nct> {
758 type Output = Self;
759 fn deposit_bits(self, mask: Self) -> Self {
760 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
763 let mut remaining = mask;
764 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
765 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
766 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
768 if !<Self as const_num_traits::Zero>::is_zero(&(self & bb)) {
769 result |= lowest;
770 }
771 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
772 remaining,
773 <Self as const_num_traits::ConstOne>::ONE,
774 );
775 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
776 }
777 result
778 }
779 }
780
781 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for FixedUInt<T, N, Nct> {
782 type Output = Self;
783 fn extract_bits(self, mask: Self) -> Self {
784 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
787 let mut remaining = mask;
788 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
789 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
790 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
791 if !<Self as const_num_traits::Zero>::is_zero(&(self & lowest)) {
792 result |= bb;
793 }
794 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
795 remaining,
796 <Self as const_num_traits::ConstOne>::ONE,
797 );
798 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
799 }
800 result
801 }
802 }
803
804 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for &FixedUInt<T, N, Nct> {
805 type Output = FixedUInt<T, N, Nct>;
806 fn deposit_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
807 <FixedUInt<T, N, Nct> as const_num_traits::DepositBits>::deposit_bits(*self, *mask)
808 }
809 }
810
811 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for &FixedUInt<T, N, Nct> {
812 type Output = FixedUInt<T, N, Nct>;
813 fn extract_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
814 <FixedUInt<T, N, Nct> as const_num_traits::ExtractBits>::extract_bits(*self, *mask)
815 }
816 }
817}
818
819#[cfg(feature = "num-traits")]
821impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
822 for FixedUInt<T, N, P>
823{
824 fn wrapping_shl(&self, bits: u32) -> Self {
825 WrappingShl::wrapping_shl(*self, bits)
826 }
827}
828
829#[cfg(feature = "num-traits")]
830impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
831 for FixedUInt<T, N, P>
832{
833 fn wrapping_shr(&self, bits: u32) -> Self {
834 WrappingShr::wrapping_shr(*self, bits)
835 }
836}
837
838#[cfg(feature = "num-traits")]
839impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
840 fn checked_shl(&self, bits: u32) -> Option<Self> {
841 CheckedShl::checked_shl(*self, bits)
842 }
843}
844
845#[cfg(feature = "num-traits")]
846impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
847 fn checked_shr(&self, bits: u32) -> Option<Self> {
848 CheckedShr::checked_shr(*self, bits)
849 }
850}
851
852#[cfg(test)]
853#[allow(clippy::op_ref)]
856mod tests {
857 use super::*;
858
859 #[test]
860 fn test_bitand_combinations() {
861 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);
867 assert_eq!(a & &b, expected);
869 assert_eq!(&a & b, expected);
871 assert_eq!(&a & &b, expected);
873 }
874
875 #[test]
876 fn test_bitor_combinations() {
877 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);
883 assert_eq!(a | &b, expected);
885 assert_eq!(&a | b, expected);
887 assert_eq!(&a | &b, expected);
889 }
890
891 #[test]
892 fn test_bitxor_combinations() {
893 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);
899 assert_eq!(a ^ &b, expected);
901 assert_eq!(&a ^ b, expected);
903 assert_eq!(&a ^ &b, expected);
905 }
906
907 #[test]
908 fn test_shl_combinations() {
909 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
911 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
915 assert_eq!(a << &shift, expected);
917 assert_eq!(&a << shift, expected);
919 assert_eq!(&a << &shift, expected);
921
922 let shift32: u32 = 2;
924 assert_eq!(a << shift32, expected);
925 assert_eq!(a << &shift32, expected);
926 assert_eq!(&a << shift32, expected);
927 assert_eq!(&a << &shift32, expected);
928 }
929
930 #[test]
931 fn test_shr_combinations() {
932 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
934 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
938 assert_eq!(a >> &shift, expected);
940 assert_eq!(&a >> shift, expected);
942 assert_eq!(&a >> &shift, expected);
944
945 let shift32: u32 = 2;
947 assert_eq!(a >> shift32, expected);
948 assert_eq!(a >> &shift32, expected);
949 assert_eq!(&a >> shift32, expected);
950 assert_eq!(&a >> &shift32, expected);
951 }
952
953 #[test]
954 fn test_const_bitops() {
955 type TestInt = FixedUInt<u8, 2>;
956
957 let a = TestInt::from(0b11001100u8);
958 let b = TestInt::from(0b10101010u8);
959
960 let not_a = !a;
962 assert_eq!(not_a.array[0], 0b00110011);
963 assert_eq!(not_a.array[1], 0xFF);
964
965 assert_eq!(a & b, TestInt::from(0b10001000u8));
967
968 assert_eq!(a | b, TestInt::from(0b11101110u8));
970
971 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
973
974 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
976
977 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
979
980 #[cfg(feature = "nightly")]
981 {
982 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
983 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
984
985 const NOT_A: TestInt = !A;
986 const AND_AB: TestInt = A & B;
987 const OR_AB: TestInt = A | B;
988 const XOR_AB: TestInt = A ^ B;
989 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
990 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
991
992 assert_eq!(NOT_A.array[0], 0b00110011);
993 assert_eq!(AND_AB.array[0], 0b10001000);
994 assert_eq!(OR_AB.array[0], 0b11101110);
995 assert_eq!(XOR_AB.array[0], 0b01100110);
996 assert_eq!(SHL_1.array[0], 16);
997 assert_eq!(SHR_16.array[0], 4);
998 }
999 }
1000
1001 #[test]
1002 fn test_const_shift_traits() {
1003 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = OverflowingShl::overflowing_shl(a, 8);
1008 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
1010
1011 let (res, overflow) = OverflowingShl::overflowing_shl(a, 16);
1012 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
1014
1015 let (res, overflow) = OverflowingShl::overflowing_shl(a, 9);
1016 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = OverflowingShr::overflowing_shr(b, 8);
1022 assert_eq!(res.array, [1, 0]); assert!(!overflow);
1024
1025 let (res, overflow) = OverflowingShr::overflowing_shr(b, 16);
1026 assert_eq!(res.array, [0, 1]); assert!(overflow);
1028
1029 let c = TestInt::from(1u8);
1031 assert_eq!(WrappingShl::wrapping_shl(c, 4).array, [16, 0]);
1032 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);
1037 assert_eq!(WrappingShr::wrapping_shr(d, 4).array, [0, 0x08]);
1038 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);
1043 assert_eq!(CheckedShl::checked_shl(e, 4), Some(TestInt::from(16u8)));
1044 assert_eq!(
1045 CheckedShl::checked_shl(e, 15),
1046 Some(TestInt::from(0x8000u16))
1047 );
1048 assert_eq!(CheckedShl::checked_shl(e, 16), None); let f = TestInt::from(0x8000u16);
1052 assert_eq!(CheckedShr::checked_shr(f, 15), Some(TestInt::from(1u8)));
1053 assert_eq!(CheckedShr::checked_shr(f, 16), None); let g = TestInt::from(42u8);
1057 assert_eq!(OverflowingShl::overflowing_shl(g, 0), (g, false));
1058 assert_eq!(OverflowingShr::overflowing_shr(g, 0), (g, false));
1059 assert_eq!(WrappingShl::wrapping_shl(g, 0), g);
1060 assert_eq!(WrappingShr::wrapping_shr(g, 0), g);
1061 assert_eq!(CheckedShl::checked_shl(g, 0), Some(g));
1062 assert_eq!(CheckedShr::checked_shr(g, 0), Some(g));
1063 }
1064
1065 #[test]
1066 fn test_const_shift_traits_n0() {
1067 type ZeroInt = FixedUInt<u8, 0>;
1069 let z = ZeroInt::from_array([]);
1070
1071 assert_eq!(OverflowingShl::overflowing_shl(z, 0), (z, true));
1073 assert_eq!(OverflowingShr::overflowing_shr(z, 0), (z, true));
1074 assert_eq!(WrappingShl::wrapping_shl(z, 0), z);
1075 assert_eq!(WrappingShr::wrapping_shr(z, 0), z);
1076 assert_eq!(CheckedShl::checked_shl(z, 0), None);
1077 assert_eq!(CheckedShr::checked_shr(z, 0), None);
1078 }
1079
1080 #[test]
1081 #[cfg(feature = "num-traits")]
1082 fn test_num_traits_shift_wrappers() {
1083 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
1084
1085 type TestInt = FixedUInt<u8, 2>;
1086
1087 let a = TestInt::from(1u8);
1088
1089 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
1091 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
1095 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
1096
1097 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
1099 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
1100
1101 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
1103 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
1104 }
1105
1106 #[test]
1107 fn test_unbounded_shift() {
1108 type U16 = FixedUInt<u8, 2>;
1109
1110 let one = U16::from(1u8);
1111
1112 assert_eq!(UnboundedShl::unbounded_shl(one, 0), one);
1114 assert_eq!(UnboundedShl::unbounded_shl(one, 4), U16::from(16u8));
1115 assert_eq!(UnboundedShl::unbounded_shl(one, 15), U16::from(0x8000u16));
1116
1117 assert_eq!(UnboundedShr::unbounded_shr(U16::from(0x8000u16), 15), one);
1118 assert_eq!(UnboundedShr::unbounded_shr(U16::from(16u8), 4), one);
1119
1120 assert_eq!(UnboundedShl::unbounded_shl(one, 16), U16::from(0u8));
1122 assert_eq!(
1123 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 16),
1124 U16::from(0u8)
1125 );
1126
1127 assert_eq!(
1129 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 17),
1130 U16::from(0u8)
1131 );
1132 assert_eq!(
1133 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 100),
1134 U16::from(0u8)
1135 );
1136 assert_eq!(
1137 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 17),
1138 U16::from(0u8)
1139 );
1140 assert_eq!(
1141 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 100),
1142 U16::from(0u8)
1143 );
1144
1145 type U32 = FixedUInt<u8, 4>;
1147 let one32 = U32::from(1u8);
1148 assert_eq!(
1149 UnboundedShl::unbounded_shl(one32, 31),
1150 U32::from(0x80000000u32)
1151 );
1152 assert_eq!(UnboundedShl::unbounded_shl(one32, 32), U32::from(0u8));
1153 assert_eq!(
1154 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 31),
1155 one32
1156 );
1157 assert_eq!(
1158 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 32),
1159 U32::from(0u8)
1160 );
1161 }
1162
1163 #[test]
1164 fn test_unbounded_shift_polymorphic() {
1165 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
1166 where
1167 T: UnboundedShl<Output = T>
1168 + UnboundedShr<Output = T>
1169 + core::ops::Shl<u32, Output = T>
1170 + core::ops::Shr<u32, Output = T>
1171 + Eq
1172 + core::fmt::Debug
1173 + Copy,
1174 {
1175 assert_eq!(UnboundedShl::unbounded_shl(val, shift), expected_shl);
1176 assert_eq!(UnboundedShr::unbounded_shr(val, shift), expected_shr);
1177 }
1178
1179 type U8x2 = FixedUInt<u8, 2>;
1181 type U8x4 = FixedUInt<u8, 4>;
1182 type U16x2 = FixedUInt<u16, 2>;
1183
1184 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
1186 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
1187 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
1188
1189 test_unbounded(1u8, 4, 16u8, 0u8);
1191 test_unbounded(1u16, 4, 16u16, 0u16);
1192 test_unbounded(1u32, 4, 16u32, 0u32);
1193
1194 test_unbounded(1u8, 8, 0u8, 0u8);
1196 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
1197 }
1198
1199 #[test]
1200 fn test_bit_width() {
1201 use const_num_traits::BitWidth;
1202 type U16 = FixedUInt<u8, 2>;
1203 assert_eq!(BitWidth::bit_width(U16::from(0u8)), 0);
1204 assert_eq!(BitWidth::bit_width(U16::from(1u8)), 1);
1205 assert_eq!(BitWidth::bit_width(U16::from(2u8)), 2);
1206 assert_eq!(BitWidth::bit_width(U16::from(3u8)), 2);
1207 assert_eq!(BitWidth::bit_width(U16::from(255u8)), 8);
1208 assert_eq!(BitWidth::bit_width(U16::from(256u16)), 9);
1209 assert_eq!(BitWidth::bit_width(U16::from(0xFFFFu16)), 16);
1210 }
1211
1212 #[test]
1213 fn test_highest_lowest_one() {
1214 use const_num_traits::{HighestOne, LowestOne};
1215 type U16 = FixedUInt<u8, 2>;
1216 assert_eq!(HighestOne::highest_one(U16::from(0u8)), None);
1217 assert_eq!(HighestOne::highest_one(U16::from(1u8)), Some(0));
1218 assert_eq!(HighestOne::highest_one(U16::from(0b1010_0000u8)), Some(7));
1219 assert_eq!(HighestOne::highest_one(U16::from(0x8000u16)), Some(15));
1220
1221 assert_eq!(LowestOne::lowest_one(U16::from(0u8)), None);
1222 assert_eq!(LowestOne::lowest_one(U16::from(1u8)), Some(0));
1223 assert_eq!(LowestOne::lowest_one(U16::from(0b0010_1000u8)), Some(3));
1224 assert_eq!(LowestOne::lowest_one(U16::from(0x8000u16)), Some(15));
1225 }
1226
1227 #[test]
1228 fn test_isolate_highest_lowest_one() {
1229 use const_num_traits::{IsolateHighestOne, IsolateLowestOne};
1230 type U16 = FixedUInt<u8, 2>;
1231 assert_eq!(
1233 IsolateHighestOne::isolate_highest_one(U16::from(0u8)),
1234 U16::from(0u8)
1235 );
1236 assert_eq!(
1237 IsolateLowestOne::isolate_lowest_one(U16::from(0u8)),
1238 U16::from(0u8)
1239 );
1240 assert_eq!(
1242 IsolateHighestOne::isolate_highest_one(U16::from(0b1010_0000u8)),
1243 U16::from(0b1000_0000u8)
1244 );
1245 assert_eq!(
1246 IsolateLowestOne::isolate_lowest_one(U16::from(0b1010_1000u8)),
1247 U16::from(0b0000_1000u8)
1248 );
1249 let p: U16 = U16::from(0x0100u16);
1251 assert_eq!(IsolateHighestOne::isolate_highest_one(p), p);
1252 assert_eq!(IsolateLowestOne::isolate_lowest_one(p), p);
1253 }
1254
1255 #[test]
1256 fn test_shl_shr_exact() {
1257 use const_num_traits::{ShlExact, ShrExact};
1258 type U16 = FixedUInt<u8, 2>;
1259 assert_eq!(
1261 ShlExact::shl_exact(U16::from(1u8), 4),
1262 Some(U16::from(16u8))
1263 );
1264 assert_eq!(ShlExact::shl_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1265 assert_eq!(ShlExact::shl_exact(U16::from(0x8000u16), 1), None);
1267 assert_eq!(ShlExact::shl_exact(U16::from(1u8), 16), None);
1269
1270 assert_eq!(
1272 ShrExact::shr_exact(U16::from(16u8), 4),
1273 Some(U16::from(1u8))
1274 );
1275 assert_eq!(ShrExact::shr_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1276 assert_eq!(ShrExact::shr_exact(U16::from(0b0001u8), 1), None);
1278 assert_eq!(ShrExact::shr_exact(U16::from(0b0011u8), 1), None);
1279 assert_eq!(ShrExact::shr_exact(U16::from(1u8), 16), None);
1281 }
1282
1283 #[test]
1284 #[allow(clippy::needless_borrows_for_generic_args)]
1285 fn test_ref_receivers_compile_through() {
1286 use const_num_traits::{BitWidth, IsolateHighestOne, IsolateLowestOne, ShlExact, ShrExact};
1287 type U16 = FixedUInt<u8, 2>;
1288 let v = U16::from(0b0010_1000u8);
1289 assert_eq!(BitWidth::bit_width(&v), 6);
1290 assert_eq!(
1291 IsolateHighestOne::isolate_highest_one(&v),
1292 U16::from(0b0010_0000u8)
1293 );
1294 assert_eq!(
1295 IsolateLowestOne::isolate_lowest_one(&v),
1296 U16::from(0b0000_1000u8)
1297 );
1298 assert_eq!(ShlExact::shl_exact(&v, 2), Some(U16::from(0b1010_0000u8)));
1299 assert_eq!(ShrExact::shr_exact(&v, 3), Some(U16::from(0b0000_0101u8)));
1300 }
1301
1302 #[test]
1303 fn test_funnel_shifts() {
1304 use const_num_traits::{FunnelShl, FunnelShr};
1305 type U16 = FixedUInt<u8, 2>;
1306
1307 assert_eq!(
1309 FunnelShl::funnel_shl(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1310 U16::from(0x0003u16),
1311 );
1312 assert_eq!(
1314 FunnelShl::funnel_shl(U16::from(0xABCDu16), U16::from(0xFFFFu16), 0),
1315 U16::from(0xABCDu16),
1316 );
1317 assert_eq!(
1319 FunnelShr::funnel_shr(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1320 U16::from(0xC000u16),
1321 );
1322 assert_eq!(
1324 FunnelShr::funnel_shr(U16::from(0xABCDu16), U16::from(0x1234u16), 0),
1325 U16::from(0x1234u16),
1326 );
1327
1328 let hi = U16::from(0x0001u16);
1330 let lo = U16::from(0x8000u16);
1331 assert_eq!(FunnelShl::funnel_shl(&hi, &lo, 1), U16::from(0x0003u16));
1332 assert_eq!(FunnelShr::funnel_shr(&hi, &lo, 1), U16::from(0xC000u16));
1333 }
1334
1335 #[test]
1336 #[should_panic(expected = "funnel_shl: n out of range")]
1337 fn test_funnel_shl_panics_at_bit_size() {
1338 use const_num_traits::FunnelShl;
1339 type U16 = FixedUInt<u8, 2>;
1340 let _ = FunnelShl::funnel_shl(U16::from(1u8), U16::from(0u8), 16);
1341 }
1342
1343 #[test]
1344 fn test_deposit_extract_bits() {
1345 use const_num_traits::Nct;
1346 use const_num_traits::{DepositBits, ExtractBits};
1347 type U16 = FixedUInt<u8, 2, Nct>;
1348
1349 assert_eq!(
1352 DepositBits::deposit_bits(U16::from(0b101u8), U16::from(0b1111_0000u8)),
1353 U16::from(0b0101_0000u8),
1354 );
1355 assert_eq!(
1357 ExtractBits::extract_bits(U16::from(0b0101_0011u8), U16::from(0b1111_0000u8)),
1358 U16::from(0b101u8),
1359 );
1360
1361 assert_eq!(
1363 DepositBits::deposit_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1364 U16::from(0u8),
1365 );
1366 assert_eq!(
1367 ExtractBits::extract_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1368 U16::from(0u8),
1369 );
1370
1371 assert_eq!(
1373 DepositBits::deposit_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1374 U16::from(0xABCDu16),
1375 );
1376 assert_eq!(
1377 ExtractBits::extract_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1378 U16::from(0xABCDu16),
1379 );
1380
1381 let mask = U16::from(0b1010_1010u8);
1385 let v = U16::from(0b1111_1111u8);
1386 let extracted = ExtractBits::extract_bits(v, mask);
1387 let redeposited = DepositBits::deposit_bits(extracted, mask);
1388 assert_eq!(redeposited, v & mask);
1389
1390 let v_ref = U16::from(0b0110_0110u8);
1392 let m_ref = U16::from(0b1111_0000u8);
1393 assert_eq!(
1394 ExtractBits::extract_bits(&v_ref, &m_ref),
1395 U16::from(0b0110u8),
1396 );
1397 assert_eq!(
1398 DepositBits::deposit_bits(&U16::from(0b101u8), &m_ref),
1399 U16::from(0b0101_0000u8),
1400 );
1401 }
1402
1403 c0nst::c0nst! {
1413 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) {
1414 OverflowingShl::overflowing_shl(v, bits)
1415 }
1416 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) {
1417 OverflowingShr::overflowing_shr(v, bits)
1418 }
1419 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> {
1420 WrappingShl::wrapping_shl(v, bits)
1421 }
1422 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> {
1423 WrappingShr::wrapping_shr(v, bits)
1424 }
1425 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>> {
1426 CheckedShl::checked_shl(v, bits)
1427 }
1428 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>> {
1429 CheckedShr::checked_shr(v, bits)
1430 }
1431 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> {
1432 UnboundedShl::unbounded_shl(v, bits)
1433 }
1434 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> {
1435 UnboundedShr::unbounded_shr(v, bits)
1436 }
1437 pub c0nst fn const_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1438 const_num_traits::HighestOne::highest_one(v)
1439 }
1440 pub c0nst fn const_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1441 const_num_traits::LowestOne::lowest_one(v)
1442 }
1443 pub c0nst fn const_bit_width<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
1444 const_num_traits::BitWidth::bit_width(v)
1445 }
1446 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> {
1447 const_num_traits::IsolateHighestOne::isolate_highest_one(v)
1448 }
1449 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> {
1450 const_num_traits::IsolateLowestOne::isolate_lowest_one(v)
1451 }
1452 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>> {
1453 const_num_traits::ShlExact::shl_exact(v, bits)
1454 }
1455 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>> {
1456 const_num_traits::ShrExact::shr_exact(v, bits)
1457 }
1458 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> {
1459 const_num_traits::FunnelShl::funnel_shl(hi, lo, n)
1460 }
1461 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> {
1462 const_num_traits::FunnelShr::funnel_shr(hi, lo, n)
1463 }
1464 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> {
1465 const_num_traits::DepositBits::deposit_bits(v, mask)
1466 }
1467 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> {
1468 const_num_traits::ExtractBits::extract_bits(v, mask)
1469 }
1470 }
1471
1472 #[test]
1473 fn nightly_const_eval_bit_traits() {
1474 type U16 = FixedUInt<u8, 2>;
1475
1476 let v = U16::from(1u8);
1478 assert_eq!(const_overflowing_shl(v, 4), (U16::from(16u8), false));
1479 assert_eq!(const_wrapping_shl(v, 4), U16::from(16u8));
1480 assert_eq!(const_checked_shl(v, 16), None);
1481 assert_eq!(const_bit_width(U16::from(0xFFu8)), 8);
1482
1483 #[cfg(feature = "nightly")]
1485 {
1486 const V: U16 = FixedUInt::from_array([1, 0]);
1487 const V_FF: U16 = FixedUInt::from_array([0xFF, 0]);
1488 const V_MASK: U16 = FixedUInt::from_array([0b1010_1000, 0]);
1489 const HI: U16 = FixedUInt::from_array([1, 0]);
1490 const LO: U16 = FixedUInt::from_array([0, 0x80]);
1491
1492 const OSHL: (U16, bool) = const_overflowing_shl(V, 4);
1493 const OSHR: (U16, bool) = const_overflowing_shr(V_FF, 4);
1494 const WSHL: U16 = const_wrapping_shl(V, 4);
1495 const WSHR: U16 = const_wrapping_shr(V_FF, 4);
1496 const CSHL: Option<U16> = const_checked_shl(V, 16);
1497 const CSHR: Option<U16> = const_checked_shr(V, 4);
1498 const USHL: U16 = const_unbounded_shl(V, 8);
1499 const USHR: U16 = const_unbounded_shr(V_FF, 4);
1500 const HI_ONE: Option<u32> = const_highest_one(V_FF);
1501 const LO_ONE: Option<u32> = const_lowest_one(V_MASK);
1502 const BW: u32 = const_bit_width(V_FF);
1503 const IH: U16 = const_isolate_highest_one(V_MASK);
1504 const IL: U16 = const_isolate_lowest_one(V_MASK);
1505 const SHLEX: Option<U16> = const_shl_exact(V, 4);
1506 const SHREX: Option<U16> = const_shr_exact(FixedUInt::from_array([16, 0]), 4);
1507 const FSHL: U16 = const_funnel_shl(HI, LO, 1);
1508 const FSHR: U16 = const_funnel_shr(HI, LO, 1);
1509 const DEP: U16 = const_deposit_bits(
1510 FixedUInt::from_array([0b101, 0]),
1511 FixedUInt::from_array([0b1111_0000, 0]),
1512 );
1513 const EXT: U16 = const_extract_bits(
1514 FixedUInt::from_array([0b0101_0011, 0]),
1515 FixedUInt::from_array([0b1111_0000, 0]),
1516 );
1517
1518 assert_eq!(OSHL.0.array, [16, 0]);
1520 assert!(!OSHL.1);
1521 assert_eq!(OSHR.0.array, [0x0F, 0]);
1522 assert!(!OSHR.1);
1523 assert_eq!(WSHL.array, [16, 0]);
1524 assert_eq!(WSHR.array, [0x0F, 0]);
1525 assert!(CSHL.is_none());
1526 assert!(CSHR.is_some());
1527 assert_eq!(USHL.array, [0, 1]);
1528 assert_eq!(USHR.array, [0x0F, 0]);
1529 assert_eq!(HI_ONE, Some(7));
1530 assert_eq!(LO_ONE, Some(3));
1531 assert_eq!(BW, 8);
1532 assert_eq!(IH.array, [0b1000_0000, 0]);
1533 assert_eq!(IL.array, [0b0000_1000, 0]);
1534 assert!(SHLEX.is_some());
1535 assert!(SHREX.is_some());
1536 assert_eq!(FSHL.array, [0x03, 0]);
1537 assert_eq!(FSHR.array, [0x00, 0xC0]);
1538 assert_eq!(DEP.array, [0b0101_0000, 0]);
1539 assert_eq!(EXT.array, [0b101, 0]);
1540 }
1541 }
1542}