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::IsolateHighestOne for FixedUInt<T, N, P> {
627 type Output = Self;
628 fn isolate_highest_one(self) -> Self {
629 let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
630 if lz as usize == Self::BIT_SIZE {
631 <Self as const_num_traits::ConstZero>::ZERO
633 } else {
634 let pos = Self::BIT_SIZE as u32 - 1 - lz;
635 <Self as const_num_traits::ConstOne>::ONE << (pos as usize)
636 }
637 }
638 }
639
640 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for FixedUInt<T, N, P> {
641 type Output = Self;
642 fn isolate_lowest_one(self) -> Self {
643 let neg = <Self as const_num_traits::WrappingSub>::wrapping_sub(
646 <Self as const_num_traits::ConstZero>::ZERO,
647 self,
648 );
649 self & neg
650 }
651 }
652
653 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for &FixedUInt<T, N, P> {
654 type Output = FixedUInt<T, N, P>;
655 fn isolate_highest_one(self) -> FixedUInt<T, N, P> {
656 <FixedUInt<T, N, P> as const_num_traits::IsolateHighestOne>::isolate_highest_one(FixedUInt::from_array(self.array))
657 }
658 }
659
660 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for &FixedUInt<T, N, P> {
661 type Output = FixedUInt<T, N, P>;
662 fn isolate_lowest_one(self) -> FixedUInt<T, N, P> {
663 <FixedUInt<T, N, P> as const_num_traits::IsolateLowestOne>::isolate_lowest_one(FixedUInt::from_array(self.array))
664 }
665 }
666
667 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for FixedUInt<T, N, P> {
680 type Output = FixedUInt<T, N, P>;
681 fn shl_exact(self, rhs: u32) -> Option<Self> {
682 if (rhs as usize) < Self::BIT_SIZE
683 && rhs <= <Self as const_num_traits::PrimBits>::leading_zeros(self)
684 {
685 Some(self << (rhs as usize))
686 } else {
687 None
688 }
689 }
690 }
691
692 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for FixedUInt<T, N, P> {
693 type Output = FixedUInt<T, N, P>;
694 fn shr_exact(self, rhs: u32) -> Option<Self> {
695 if (rhs as usize) < Self::BIT_SIZE
696 && rhs <= <Self as const_num_traits::PrimBits>::trailing_zeros(self)
697 {
698 Some(self >> (rhs as usize))
699 } else {
700 None
701 }
702 }
703 }
704
705 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for &FixedUInt<T, N, P> {
706 type Output = FixedUInt<T, N, P>;
707 fn shl_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
708 <FixedUInt<T, N, P> as const_num_traits::ShlExact>::shl_exact(FixedUInt::from_array(self.array), rhs)
709 }
710 }
711
712 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for &FixedUInt<T, N, P> {
713 type Output = FixedUInt<T, N, P>;
714 fn shr_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
715 <FixedUInt<T, N, P> as const_num_traits::ShrExact>::shr_exact(FixedUInt::from_array(self.array), rhs)
716 }
717 }
718
719 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for FixedUInt<T, N, P> {
729 type Output = Self;
730 fn funnel_shl(self, rhs: Self, n: u32) -> Self {
731 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shl: n out of range");
732 if n == 0 {
733 self
734 } else {
735 let lo_shift = Self::BIT_SIZE as u32 - n;
736 (self << (n as usize)) | (rhs >> (lo_shift as usize))
737 }
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 = Self;
743 fn funnel_shr(self, rhs: Self, n: u32) -> Self {
744 assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shr: n out of range");
745 if n == 0 {
746 rhs
747 } else {
748 let hi_shift = Self::BIT_SIZE as u32 - n;
749 (rhs >> (n as usize)) | (self << (hi_shift as usize))
750 }
751 }
752 }
753
754 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for &FixedUInt<T, N, P> {
755 type Output = FixedUInt<T, N, P>;
756 fn funnel_shl(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
757 <FixedUInt<T, N, P> as const_num_traits::FunnelShl>::funnel_shl(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
758 }
759 }
760
761 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for &FixedUInt<T, N, P> {
762 type Output = FixedUInt<T, N, P>;
763 fn funnel_shr(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
764 <FixedUInt<T, N, P> as const_num_traits::FunnelShr>::funnel_shr(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array), n)
765 }
766 }
767
768 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for FixedUInt<T, N, Nct> {
778 type Output = Self;
779 fn deposit_bits(self, mask: Self) -> Self {
780 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
783 let mut remaining = mask;
784 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
785 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
786 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
788 if !<Self as const_num_traits::Zero>::is_zero(&(self & bb)) {
789 result |= lowest;
790 }
791 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
792 remaining,
793 <Self as const_num_traits::ConstOne>::ONE,
794 );
795 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
796 }
797 result
798 }
799 }
800
801 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for FixedUInt<T, N, Nct> {
802 type Output = Self;
803 fn extract_bits(self, mask: Self) -> Self {
804 let mut result = <Self as const_num_traits::ConstZero>::ZERO;
807 let mut remaining = mask;
808 let mut bb = <Self as const_num_traits::ConstOne>::ONE;
809 while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
810 let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
811 if !<Self as const_num_traits::Zero>::is_zero(&(self & lowest)) {
812 result |= bb;
813 }
814 remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
815 remaining,
816 <Self as const_num_traits::ConstOne>::ONE,
817 );
818 bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
819 }
820 result
821 }
822 }
823
824 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for &FixedUInt<T, N, Nct> {
825 type Output = FixedUInt<T, N, Nct>;
826 fn deposit_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
827 <FixedUInt<T, N, Nct> as const_num_traits::DepositBits>::deposit_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
828 }
829 }
830
831 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for &FixedUInt<T, N, Nct> {
832 type Output = FixedUInt<T, N, Nct>;
833 fn extract_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
834 <FixedUInt<T, N, Nct> as const_num_traits::ExtractBits>::extract_bits(FixedUInt::from_array(self.array), FixedUInt::from_array(mask.array))
835 }
836 }
837}
838
839#[cfg(feature = "num-traits")]
841impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
842 for FixedUInt<T, N, P>
843{
844 fn wrapping_shl(&self, bits: u32) -> Self {
845 <&Self as WrappingShl>::wrapping_shl(self, bits)
846 }
847}
848
849#[cfg(feature = "num-traits")]
850impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
851 for FixedUInt<T, N, P>
852{
853 fn wrapping_shr(&self, bits: u32) -> Self {
854 <&Self as WrappingShr>::wrapping_shr(self, bits)
855 }
856}
857
858#[cfg(feature = "num-traits")]
859impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
860 fn checked_shl(&self, bits: u32) -> Option<Self> {
861 <&Self as CheckedShl>::checked_shl(self, bits)
862 }
863}
864
865#[cfg(feature = "num-traits")]
866impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
867 fn checked_shr(&self, bits: u32) -> Option<Self> {
868 <&Self as CheckedShr>::checked_shr(self, bits)
869 }
870}
871
872#[cfg(test)]
873#[allow(clippy::op_ref)]
876mod tests {
877 use super::*;
878
879 #[test]
880 fn test_bitand_combinations() {
881 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);
887 assert_eq!(a & &b, expected);
889 assert_eq!(&a & b, expected);
891 assert_eq!(&a & &b, expected);
893 }
894
895 #[test]
896 fn test_bitor_combinations() {
897 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);
903 assert_eq!(a | &b, expected);
905 assert_eq!(&a | b, expected);
907 assert_eq!(&a | &b, expected);
909 }
910
911 #[test]
912 fn test_bitxor_combinations() {
913 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);
919 assert_eq!(a ^ &b, expected);
921 assert_eq!(&a ^ b, expected);
923 assert_eq!(&a ^ &b, expected);
925 }
926
927 #[test]
928 fn test_shl_combinations() {
929 let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
931 let expected = FixedUInt::<u8, 2>::from(8u8); assert_eq!(a << shift, expected);
935 assert_eq!(a << &shift, expected);
937 assert_eq!(&a << shift, expected);
939 assert_eq!(&a << &shift, expected);
941
942 let shift32: u32 = 2;
944 assert_eq!(a << shift32, expected);
945 assert_eq!(a << &shift32, expected);
946 assert_eq!(&a << shift32, expected);
947 assert_eq!(&a << &shift32, expected);
948 }
949
950 #[test]
951 fn test_shr_combinations() {
952 let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
954 let expected = FixedUInt::<u8, 2>::from(2u8); assert_eq!(a >> shift, expected);
958 assert_eq!(a >> &shift, expected);
960 assert_eq!(&a >> shift, expected);
962 assert_eq!(&a >> &shift, expected);
964
965 let shift32: u32 = 2;
967 assert_eq!(a >> shift32, expected);
968 assert_eq!(a >> &shift32, expected);
969 assert_eq!(&a >> shift32, expected);
970 assert_eq!(&a >> &shift32, expected);
971 }
972
973 #[test]
974 fn test_const_bitops() {
975 type TestInt = FixedUInt<u8, 2>;
976
977 let a = TestInt::from(0b11001100u8);
978 let b = TestInt::from(0b10101010u8);
979
980 let not_a = !a;
982 assert_eq!(not_a.array[0], 0b00110011);
983 assert_eq!(not_a.array[1], 0xFF);
984
985 assert_eq!(a & b, TestInt::from(0b10001000u8));
987
988 assert_eq!(a | b, TestInt::from(0b11101110u8));
990
991 assert_eq!(a ^ b, TestInt::from(0b01100110u8));
993
994 assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
996
997 assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
999
1000 #[cfg(feature = "nightly")]
1001 {
1002 const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
1003 const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
1004
1005 const NOT_A: TestInt = !A;
1006 const AND_AB: TestInt = A & B;
1007 const OR_AB: TestInt = A | B;
1008 const XOR_AB: TestInt = A ^ B;
1009 const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
1010 const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
1011
1012 assert_eq!(NOT_A.array[0], 0b00110011);
1013 assert_eq!(AND_AB.array[0], 0b10001000);
1014 assert_eq!(OR_AB.array[0], 0b11101110);
1015 assert_eq!(XOR_AB.array[0], 0b01100110);
1016 assert_eq!(SHL_1.array[0], 16);
1017 assert_eq!(SHR_16.array[0], 4);
1018 }
1019 }
1020
1021 #[test]
1022 fn test_const_shift_traits() {
1023 type TestInt = FixedUInt<u8, 2>; let a = TestInt::from(0x80u8); let (res, overflow) = OverflowingShl::overflowing_shl(a, 8);
1028 assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
1030
1031 let (res, overflow) = OverflowingShl::overflowing_shl(a, 16);
1032 assert_eq!(res.array, [0x80, 0]); assert!(overflow);
1034
1035 let (res, overflow) = OverflowingShl::overflowing_shl(a, 9);
1036 assert_eq!(res.array, [0, 0]); assert!(!overflow); let b = TestInt::from(0x0100u16); let (res, overflow) = OverflowingShr::overflowing_shr(b, 8);
1042 assert_eq!(res.array, [1, 0]); assert!(!overflow);
1044
1045 let (res, overflow) = OverflowingShr::overflowing_shr(b, 16);
1046 assert_eq!(res.array, [0, 1]); assert!(overflow);
1048
1049 let c = TestInt::from(1u8);
1051 assert_eq!(WrappingShl::wrapping_shl(c, 4).array, [16, 0]);
1052 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);
1057 assert_eq!(WrappingShr::wrapping_shr(d, 4).array, [0, 0x08]);
1058 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);
1063 assert_eq!(CheckedShl::checked_shl(e, 4), Some(TestInt::from(16u8)));
1064 assert_eq!(
1065 CheckedShl::checked_shl(e, 15),
1066 Some(TestInt::from(0x8000u16))
1067 );
1068 assert_eq!(CheckedShl::checked_shl(e, 16), None); let f = TestInt::from(0x8000u16);
1072 assert_eq!(CheckedShr::checked_shr(f, 15), Some(TestInt::from(1u8)));
1073 assert_eq!(CheckedShr::checked_shr(f, 16), None); let g = TestInt::from(42u8);
1077 assert_eq!(OverflowingShl::overflowing_shl(g, 0), (g, false));
1078 assert_eq!(OverflowingShr::overflowing_shr(g, 0), (g, false));
1079 assert_eq!(WrappingShl::wrapping_shl(g, 0), g);
1080 assert_eq!(WrappingShr::wrapping_shr(g, 0), g);
1081 assert_eq!(CheckedShl::checked_shl(g, 0), Some(g));
1082 assert_eq!(CheckedShr::checked_shr(g, 0), Some(g));
1083 }
1084
1085 #[test]
1086 fn test_const_shift_traits_n0() {
1087 type ZeroInt = FixedUInt<u8, 0>;
1089 let z = ZeroInt::from_array([]);
1090
1091 assert_eq!(OverflowingShl::overflowing_shl(z, 0), (z, true));
1093 assert_eq!(OverflowingShr::overflowing_shr(z, 0), (z, true));
1094 assert_eq!(WrappingShl::wrapping_shl(z, 0), z);
1095 assert_eq!(WrappingShr::wrapping_shr(z, 0), z);
1096 assert_eq!(CheckedShl::checked_shl(z, 0), None);
1097 assert_eq!(CheckedShr::checked_shr(z, 0), None);
1098 }
1099
1100 #[test]
1101 #[cfg(feature = "num-traits")]
1102 fn test_num_traits_shift_wrappers() {
1103 use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
1104
1105 type TestInt = FixedUInt<u8, 2>;
1106
1107 let a = TestInt::from(1u8);
1108
1109 assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
1111 assert_eq!(WrappingShl::wrapping_shl(&a, 16), a); let b = TestInt::from(16u8);
1115 assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
1116
1117 assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
1119 assert_eq!(CheckedShl::checked_shl(&a, 16), None);
1120
1121 assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
1123 assert_eq!(CheckedShr::checked_shr(&b, 16), None);
1124 }
1125
1126 #[test]
1127 fn test_unbounded_shift() {
1128 type U16 = FixedUInt<u8, 2>;
1129
1130 let one = U16::from(1u8);
1131
1132 assert_eq!(UnboundedShl::unbounded_shl(one, 0), one);
1134 assert_eq!(UnboundedShl::unbounded_shl(one, 4), U16::from(16u8));
1135 assert_eq!(UnboundedShl::unbounded_shl(one, 15), U16::from(0x8000u16));
1136
1137 assert_eq!(UnboundedShr::unbounded_shr(U16::from(0x8000u16), 15), one);
1138 assert_eq!(UnboundedShr::unbounded_shr(U16::from(16u8), 4), one);
1139
1140 assert_eq!(UnboundedShl::unbounded_shl(one, 16), U16::from(0u8));
1142 assert_eq!(
1143 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 16),
1144 U16::from(0u8)
1145 );
1146
1147 assert_eq!(
1149 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 17),
1150 U16::from(0u8)
1151 );
1152 assert_eq!(
1153 UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 100),
1154 U16::from(0u8)
1155 );
1156 assert_eq!(
1157 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 17),
1158 U16::from(0u8)
1159 );
1160 assert_eq!(
1161 UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 100),
1162 U16::from(0u8)
1163 );
1164
1165 type U32 = FixedUInt<u8, 4>;
1167 let one32 = U32::from(1u8);
1168 assert_eq!(
1169 UnboundedShl::unbounded_shl(one32, 31),
1170 U32::from(0x80000000u32)
1171 );
1172 assert_eq!(UnboundedShl::unbounded_shl(one32, 32), U32::from(0u8));
1173 assert_eq!(
1174 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 31),
1175 one32
1176 );
1177 assert_eq!(
1178 UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 32),
1179 U32::from(0u8)
1180 );
1181 }
1182
1183 #[test]
1184 fn test_unbounded_shift_polymorphic() {
1185 fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
1186 where
1187 T: UnboundedShl<Output = T> + UnboundedShr<Output = T> + Eq + core::fmt::Debug + Copy,
1188 {
1189 assert_eq!(UnboundedShl::unbounded_shl(val, shift), expected_shl);
1190 assert_eq!(UnboundedShr::unbounded_shr(val, shift), expected_shr);
1191 }
1192
1193 type U8x2 = FixedUInt<u8, 2>;
1195 type U8x4 = FixedUInt<u8, 4>;
1196 type U16x2 = FixedUInt<u16, 2>;
1197
1198 test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
1200 test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
1201 test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
1202
1203 test_unbounded(1u8, 4, 16u8, 0u8);
1205 test_unbounded(1u16, 4, 16u16, 0u16);
1206 test_unbounded(1u32, 4, 16u32, 0u32);
1207
1208 test_unbounded(1u8, 8, 0u8, 0u8);
1210 test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
1211 }
1212
1213 #[test]
1214 fn test_bit_width() {
1215 use const_num_traits::BitWidth;
1216 type U16 = FixedUInt<u8, 2>;
1217 assert_eq!(BitWidth::bit_width(U16::from(0u8)), 0);
1218 assert_eq!(BitWidth::bit_width(U16::from(1u8)), 1);
1219 assert_eq!(BitWidth::bit_width(U16::from(2u8)), 2);
1220 assert_eq!(BitWidth::bit_width(U16::from(3u8)), 2);
1221 assert_eq!(BitWidth::bit_width(U16::from(255u8)), 8);
1222 assert_eq!(BitWidth::bit_width(U16::from(256u16)), 9);
1223 assert_eq!(BitWidth::bit_width(U16::from(0xFFFFu16)), 16);
1224 }
1225
1226 #[test]
1227 fn test_highest_lowest_one() {
1228 use const_num_traits::{HighestOne, LowestOne};
1229 type U16 = FixedUInt<u8, 2>;
1230 assert_eq!(HighestOne::highest_one(U16::from(0u8)), None);
1231 assert_eq!(HighestOne::highest_one(U16::from(1u8)), Some(0));
1232 assert_eq!(HighestOne::highest_one(U16::from(0b1010_0000u8)), Some(7));
1233 assert_eq!(HighestOne::highest_one(U16::from(0x8000u16)), Some(15));
1234
1235 assert_eq!(LowestOne::lowest_one(U16::from(0u8)), None);
1236 assert_eq!(LowestOne::lowest_one(U16::from(1u8)), Some(0));
1237 assert_eq!(LowestOne::lowest_one(U16::from(0b0010_1000u8)), Some(3));
1238 assert_eq!(LowestOne::lowest_one(U16::from(0x8000u16)), Some(15));
1239 }
1240
1241 #[test]
1242 fn test_isolate_highest_lowest_one() {
1243 use const_num_traits::{IsolateHighestOne, IsolateLowestOne};
1244 type U16 = FixedUInt<u8, 2>;
1245 assert_eq!(
1247 IsolateHighestOne::isolate_highest_one(U16::from(0u8)),
1248 U16::from(0u8)
1249 );
1250 assert_eq!(
1251 IsolateLowestOne::isolate_lowest_one(U16::from(0u8)),
1252 U16::from(0u8)
1253 );
1254 assert_eq!(
1256 IsolateHighestOne::isolate_highest_one(U16::from(0b1010_0000u8)),
1257 U16::from(0b1000_0000u8)
1258 );
1259 assert_eq!(
1260 IsolateLowestOne::isolate_lowest_one(U16::from(0b1010_1000u8)),
1261 U16::from(0b0000_1000u8)
1262 );
1263 let p: U16 = U16::from(0x0100u16);
1265 assert_eq!(IsolateHighestOne::isolate_highest_one(p), p);
1266 assert_eq!(IsolateLowestOne::isolate_lowest_one(p), p);
1267 }
1268
1269 #[test]
1270 fn test_shl_shr_exact() {
1271 use const_num_traits::{ShlExact, ShrExact};
1272 type U16 = FixedUInt<u8, 2>;
1273 assert_eq!(
1275 ShlExact::shl_exact(U16::from(1u8), 4),
1276 Some(U16::from(16u8))
1277 );
1278 assert_eq!(ShlExact::shl_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1279 assert_eq!(ShlExact::shl_exact(U16::from(0x8000u16), 1), None);
1281 assert_eq!(ShlExact::shl_exact(U16::from(1u8), 16), None);
1283
1284 assert_eq!(
1286 ShrExact::shr_exact(U16::from(16u8), 4),
1287 Some(U16::from(1u8))
1288 );
1289 assert_eq!(ShrExact::shr_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
1290 assert_eq!(ShrExact::shr_exact(U16::from(0b0001u8), 1), None);
1292 assert_eq!(ShrExact::shr_exact(U16::from(0b0011u8), 1), None);
1293 assert_eq!(ShrExact::shr_exact(U16::from(1u8), 16), None);
1295 }
1296
1297 #[test]
1298 #[allow(clippy::needless_borrows_for_generic_args)]
1299 fn test_ref_receivers_compile_through() {
1300 use const_num_traits::{BitWidth, IsolateHighestOne, IsolateLowestOne, ShlExact, ShrExact};
1301 type U16 = FixedUInt<u8, 2>;
1302 let v = U16::from(0b0010_1000u8);
1303 assert_eq!(BitWidth::bit_width(&v), 6);
1304 assert_eq!(
1305 IsolateHighestOne::isolate_highest_one(&v),
1306 U16::from(0b0010_0000u8)
1307 );
1308 assert_eq!(
1309 IsolateLowestOne::isolate_lowest_one(&v),
1310 U16::from(0b0000_1000u8)
1311 );
1312 assert_eq!(ShlExact::shl_exact(&v, 2), Some(U16::from(0b1010_0000u8)));
1313 assert_eq!(ShrExact::shr_exact(&v, 3), Some(U16::from(0b0000_0101u8)));
1314 }
1315
1316 #[test]
1317 fn test_funnel_shifts() {
1318 use const_num_traits::{FunnelShl, FunnelShr};
1319 type U16 = FixedUInt<u8, 2>;
1320
1321 assert_eq!(
1323 FunnelShl::funnel_shl(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1324 U16::from(0x0003u16),
1325 );
1326 assert_eq!(
1328 FunnelShl::funnel_shl(U16::from(0xABCDu16), U16::from(0xFFFFu16), 0),
1329 U16::from(0xABCDu16),
1330 );
1331 assert_eq!(
1333 FunnelShr::funnel_shr(U16::from(0x0001u16), U16::from(0x8000u16), 1),
1334 U16::from(0xC000u16),
1335 );
1336 assert_eq!(
1338 FunnelShr::funnel_shr(U16::from(0xABCDu16), U16::from(0x1234u16), 0),
1339 U16::from(0x1234u16),
1340 );
1341
1342 let hi = U16::from(0x0001u16);
1344 let lo = U16::from(0x8000u16);
1345 assert_eq!(FunnelShl::funnel_shl(&hi, &lo, 1), U16::from(0x0003u16));
1346 assert_eq!(FunnelShr::funnel_shr(&hi, &lo, 1), U16::from(0xC000u16));
1347 }
1348
1349 #[test]
1350 #[should_panic(expected = "funnel_shl: n out of range")]
1351 fn test_funnel_shl_panics_at_bit_size() {
1352 use const_num_traits::FunnelShl;
1353 type U16 = FixedUInt<u8, 2>;
1354 let _ = FunnelShl::funnel_shl(U16::from(1u8), U16::from(0u8), 16);
1355 }
1356
1357 #[test]
1358 fn test_deposit_extract_bits() {
1359 use const_num_traits::Nct;
1360 use const_num_traits::{DepositBits, ExtractBits};
1361 type U16 = FixedUInt<u8, 2, Nct>;
1362
1363 assert_eq!(
1366 DepositBits::deposit_bits(U16::from(0b101u8), U16::from(0b1111_0000u8)),
1367 U16::from(0b0101_0000u8),
1368 );
1369 assert_eq!(
1371 ExtractBits::extract_bits(U16::from(0b0101_0011u8), U16::from(0b1111_0000u8)),
1372 U16::from(0b101u8),
1373 );
1374
1375 assert_eq!(
1377 DepositBits::deposit_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1378 U16::from(0u8),
1379 );
1380 assert_eq!(
1381 ExtractBits::extract_bits(U16::from(0xFFFFu16), U16::from(0u8)),
1382 U16::from(0u8),
1383 );
1384
1385 assert_eq!(
1387 DepositBits::deposit_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1388 U16::from(0xABCDu16),
1389 );
1390 assert_eq!(
1391 ExtractBits::extract_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
1392 U16::from(0xABCDu16),
1393 );
1394
1395 let mask = U16::from(0b1010_1010u8);
1399 let v = U16::from(0b1111_1111u8);
1400 let extracted = ExtractBits::extract_bits(v, mask);
1401 let redeposited = DepositBits::deposit_bits(extracted, mask);
1402 assert_eq!(redeposited, v & mask);
1403
1404 let v_ref = U16::from(0b0110_0110u8);
1406 let m_ref = U16::from(0b1111_0000u8);
1407 assert_eq!(
1408 ExtractBits::extract_bits(&v_ref, &m_ref),
1409 U16::from(0b0110u8),
1410 );
1411 assert_eq!(
1412 DepositBits::deposit_bits(&U16::from(0b101u8), &m_ref),
1413 U16::from(0b0101_0000u8),
1414 );
1415 }
1416
1417 c0nst::c0nst! {
1427 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) {
1428 OverflowingShl::overflowing_shl(v, bits)
1429 }
1430 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) {
1431 OverflowingShr::overflowing_shr(v, bits)
1432 }
1433 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> {
1434 WrappingShl::wrapping_shl(v, bits)
1435 }
1436 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> {
1437 WrappingShr::wrapping_shr(v, bits)
1438 }
1439 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>> {
1440 CheckedShl::checked_shl(v, bits)
1441 }
1442 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>> {
1443 CheckedShr::checked_shr(v, bits)
1444 }
1445 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> {
1446 UnboundedShl::unbounded_shl(v, bits)
1447 }
1448 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> {
1449 UnboundedShr::unbounded_shr(v, bits)
1450 }
1451 pub c0nst fn const_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1452 const_num_traits::HighestOne::highest_one(v)
1453 }
1454 pub c0nst fn const_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
1455 const_num_traits::LowestOne::lowest_one(v)
1456 }
1457 pub c0nst fn const_bit_width<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
1458 const_num_traits::BitWidth::bit_width(v)
1459 }
1460 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> {
1461 const_num_traits::IsolateHighestOne::isolate_highest_one(v)
1462 }
1463 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> {
1464 const_num_traits::IsolateLowestOne::isolate_lowest_one(v)
1465 }
1466 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>> {
1467 const_num_traits::ShlExact::shl_exact(v, bits)
1468 }
1469 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>> {
1470 const_num_traits::ShrExact::shr_exact(v, bits)
1471 }
1472 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> {
1473 const_num_traits::FunnelShl::funnel_shl(hi, lo, n)
1474 }
1475 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> {
1476 const_num_traits::FunnelShr::funnel_shr(hi, lo, n)
1477 }
1478 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> {
1479 const_num_traits::DepositBits::deposit_bits(v, mask)
1480 }
1481 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> {
1482 const_num_traits::ExtractBits::extract_bits(v, mask)
1483 }
1484 }
1485
1486 #[test]
1487 fn nightly_const_eval_bit_traits() {
1488 type U16 = FixedUInt<u8, 2>;
1489
1490 let v = U16::from(1u8);
1492 assert_eq!(const_overflowing_shl(v, 4), (U16::from(16u8), false));
1493 assert_eq!(const_wrapping_shl(v, 4), U16::from(16u8));
1494 assert_eq!(const_checked_shl(v, 16), None);
1495 assert_eq!(const_bit_width(U16::from(0xFFu8)), 8);
1496
1497 #[cfg(feature = "nightly")]
1499 {
1500 const V: U16 = FixedUInt::from_array([1, 0]);
1501 const V_FF: U16 = FixedUInt::from_array([0xFF, 0]);
1502 const V_MASK: U16 = FixedUInt::from_array([0b1010_1000, 0]);
1503 const HI: U16 = FixedUInt::from_array([1, 0]);
1504 const LO: U16 = FixedUInt::from_array([0, 0x80]);
1505
1506 const OSHL: (U16, bool) = const_overflowing_shl(V, 4);
1507 const OSHR: (U16, bool) = const_overflowing_shr(V_FF, 4);
1508 const WSHL: U16 = const_wrapping_shl(V, 4);
1509 const WSHR: U16 = const_wrapping_shr(V_FF, 4);
1510 const CSHL: Option<U16> = const_checked_shl(V, 16);
1511 const CSHR: Option<U16> = const_checked_shr(V, 4);
1512 const USHL: U16 = const_unbounded_shl(V, 8);
1513 const USHR: U16 = const_unbounded_shr(V_FF, 4);
1514 const HI_ONE: Option<u32> = const_highest_one(V_FF);
1515 const LO_ONE: Option<u32> = const_lowest_one(V_MASK);
1516 const BW: u32 = const_bit_width(V_FF);
1517 const IH: U16 = const_isolate_highest_one(V_MASK);
1518 const IL: U16 = const_isolate_lowest_one(V_MASK);
1519 const SHLEX: Option<U16> = const_shl_exact(V, 4);
1520 const SHREX: Option<U16> = const_shr_exact(FixedUInt::from_array([16, 0]), 4);
1521 const FSHL: U16 = const_funnel_shl(HI, LO, 1);
1522 const FSHR: U16 = const_funnel_shr(HI, LO, 1);
1523 const DEP: U16 = const_deposit_bits(
1524 FixedUInt::from_array([0b101, 0]),
1525 FixedUInt::from_array([0b1111_0000, 0]),
1526 );
1527 const EXT: U16 = const_extract_bits(
1528 FixedUInt::from_array([0b0101_0011, 0]),
1529 FixedUInt::from_array([0b1111_0000, 0]),
1530 );
1531
1532 assert_eq!(OSHL.0.array, [16, 0]);
1534 assert!(!OSHL.1);
1535 assert_eq!(OSHR.0.array, [0x0F, 0]);
1536 assert!(!OSHR.1);
1537 assert_eq!(WSHL.array, [16, 0]);
1538 assert_eq!(WSHR.array, [0x0F, 0]);
1539 assert!(CSHL.is_none());
1540 assert!(CSHR.is_some());
1541 assert_eq!(USHL.array, [0, 1]);
1542 assert_eq!(USHR.array, [0x0F, 0]);
1543 assert_eq!(HI_ONE, Some(7));
1544 assert_eq!(LO_ONE, Some(3));
1545 assert_eq!(BW, 8);
1546 assert_eq!(IH.array, [0b1000_0000, 0]);
1547 assert_eq!(IL.array, [0b0000_1000, 0]);
1548 assert!(SHLEX.is_some());
1549 assert!(SHREX.is_some());
1550 assert_eq!(FSHL.array, [0x03, 0]);
1551 assert_eq!(FSHR.array, [0x00, 0xC0]);
1552 assert_eq!(DEP.array, [0b0101_0000, 0]);
1553 assert_eq!(EXT.array, [0b101, 0]);
1554 }
1555 }
1556}