1use super::{
2 FixedUInt, MachineWord, const_leading_zeros, const_leading_zeros_ct, const_trailing_zeros,
3 const_trailing_zeros_ct,
4};
5use crate::machineword::ConstMachineWord;
6use const_num_traits::PrimBits;
7use const_num_traits::{Bounded, Nct, Personality, PersonalityTag};
8
9c0nst::c0nst! {
10 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> PrimBits for FixedUInt<T, N, P> {
11 fn count_ones(self) -> u32 {
17 let mut count = 0u32;
18 let mut i = 0;
19 while i < N {
20 count += self.array[i].count_ones();
21 i += 1;
22 }
23 count
24 }
25 fn count_zeros(self) -> u32 {
26 let mut count = 0u32;
27 let mut i = 0;
28 while i < N {
29 count += self.array[i].count_zeros();
30 i += 1;
31 }
32 count
33 }
34 fn leading_zeros(self) -> u32 {
35 match P::TAG {
36 PersonalityTag::Nct => const_leading_zeros(&self.array),
37 PersonalityTag::Ct => const_leading_zeros_ct(&self.array),
38 }
39 }
40 fn trailing_zeros(self) -> u32 {
41 match P::TAG {
42 PersonalityTag::Nct => const_trailing_zeros(&self.array),
43 PersonalityTag::Ct => const_trailing_zeros_ct(&self.array),
44 }
45 }
46 fn swap_bytes(self) -> Self {
47 let mut ret = <Self as const_num_traits::ConstZero>::ZERO;
48 let mut i = 0;
49 while i < N {
50 ret.array[i] = self.array[N - 1 - i].swap_bytes();
51 i += 1;
52 }
53 ret
54 }
55 fn rotate_left(self, n: u32) -> Self {
56 let bit_size = Self::BIT_SIZE as u32;
57 if bit_size == 0 {
58 return self;
59 }
60 let shift = n % bit_size;
61 let a = core::ops::Shl::<u32>::shl(self, shift);
62 let b = core::ops::Shr::<u32>::shr(self, bit_size - shift);
63 core::ops::BitOr::bitor(a, b)
64 }
65 fn rotate_right(self, n: u32) -> Self {
66 let bit_size = Self::BIT_SIZE as u32;
67 if bit_size == 0 {
68 return self;
69 }
70 let shift = n % bit_size;
71 let a = core::ops::Shr::<u32>::shr(self, shift);
72 let b = core::ops::Shl::<u32>::shl(self, bit_size - shift);
73 core::ops::BitOr::bitor(a, b)
74 }
75 fn unsigned_shl(self, n: u32) -> Self {
76 core::ops::Shl::<u32>::shl(self, n)
77 }
78 fn unsigned_shr(self, n: u32) -> Self {
79 core::ops::Shr::<u32>::shr(self, n)
80 }
81 fn signed_shl(self, n: u32) -> Self {
82 core::ops::Shl::<u32>::shl(self, n)
86 }
87 fn signed_shr(self, n: u32) -> Self {
88 let logical = core::ops::Shr::<u32>::shr(self, n);
98 if N == 0 {
99 return logical;
100 }
101 let word_bits = FixedUInt::<T, N>::WORD_BITS;
102 let sign_bit = self.array[N - 1] >> (word_bits - 1);
103 let mask_word =
104 <T as core::ops::Mul>::mul(sign_bit, <T as Bounded>::max_value());
105 let mut sign_full = self;
106 let mut i = 0;
107 while i < N {
108 sign_full.array[i] = mask_word;
109 i += 1;
110 }
111 let sf_shr = core::ops::Shr::<u32>::shr(sign_full, n);
112 let mut result = logical;
113 let mut i = 0;
114 while i < N {
115 let fill = <T as core::ops::BitXor>::bitxor(mask_word, sf_shr.array[i]);
116 result.array[i] = <T as core::ops::BitOr>::bitor(logical.array[i], fill);
117 i += 1;
118 }
119 result
120 }
121 fn reverse_bits(self) -> Self {
122 let mut ret = <Self as const_num_traits::ConstZero>::ZERO;
123 let mut i = 0;
124 while i < N {
125 ret.array[N - 1 - i] = self.array[i].reverse_bits();
126 i += 1;
127 }
128 ret
129 }
130 fn from_be(x: Self) -> Self {
132 x.swap_bytes()
133 }
134 fn from_le(x: Self) -> Self {
135 x
136 }
137 fn to_be(self) -> Self {
138 self.swap_bytes()
139 }
140 fn to_le(self) -> Self {
141 self
142 }
143 }
144}
145
146c0nst::c0nst! {
147 pub(crate) c0nst fn pow_impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
151 v: FixedUInt<T, N, Nct>, exp: u32,
152 ) -> FixedUInt<T, N, Nct> {
153 if exp == 0 {
154 return <FixedUInt<T, N, Nct> as const_num_traits::ConstOne>::ONE;
155 }
156 let mut result = <FixedUInt<T, N, Nct> as const_num_traits::ConstOne>::ONE;
157 let mut base = v;
158 let mut e = exp;
159 while e > 0 {
160 if (e & 1) == 1 {
161 result = core::ops::Mul::mul(result, base);
162 }
163 e >>= 1;
164 if e > 0 {
165 base = core::ops::Mul::mul(base, base);
166 }
167 }
168 result
169 }
170}
171
172impl<T: ConstMachineWord + MachineWord, const N: usize> FixedUInt<T, N, Nct> {
173 pub fn pow(self, exp: u32) -> Self {
179 pow_impl(self, exp)
180 }
181}
182
183#[cfg(feature = "num-traits")]
184impl<T: MachineWord, const N: usize> num_traits::PrimInt for FixedUInt<T, N, Nct> {
185 fn count_ones(self) -> u32 {
186 self.array.iter().map(|&val| val.count_ones()).sum()
187 }
188 fn count_zeros(self) -> u32 {
189 self.array.iter().map(|&val| val.count_zeros()).sum()
190 }
191 fn leading_zeros(self) -> u32 {
192 const_leading_zeros(&self.array)
193 }
194 fn trailing_zeros(self) -> u32 {
195 const_trailing_zeros(&self.array)
196 }
197 fn rotate_left(self, bits: u32) -> Self {
198 let bit_size = Self::BIT_SIZE as u32;
199 if bit_size == 0 {
200 return self;
201 }
202 let shift = bits % bit_size;
203 let a = self << shift;
204 let b = self >> (bit_size - shift);
205 a | b
206 }
207 fn rotate_right(self, bits: u32) -> Self {
208 let bit_size = Self::BIT_SIZE as u32;
209 if bit_size == 0 {
210 return self;
211 }
212 let shift = bits % bit_size;
213 let a = self >> shift;
214 let b = self << (bit_size - shift);
215 a | b
216 }
217 fn signed_shl(self, bits: u32) -> Self {
218 <Self as num_traits::PrimInt>::unsigned_shl(self, bits)
219 }
220 fn signed_shr(self, bits: u32) -> Self {
221 <Self as PrimBits>::signed_shr(self, bits)
224 }
225 fn unsigned_shl(self, bits: u32) -> Self {
226 self << bits
227 }
228 fn unsigned_shr(self, bits: u32) -> Self {
229 self >> bits
230 }
231 fn swap_bytes(self) -> Self {
232 let mut ret = Self::new();
233 for index in 0..N {
234 ret.array[index] = self.array[N - 1 - index].swap_bytes();
235 }
236
237 ret
238 }
239 fn from_be(source: Self) -> Self {
241 <Self as num_traits::PrimInt>::swap_bytes(source)
242 }
243 fn from_le(source: Self) -> Self {
244 source
245 }
246 fn to_be(self) -> Self {
247 <Self as num_traits::PrimInt>::swap_bytes(self)
248 }
249 fn to_le(self) -> Self {
250 self
251 }
252 fn pow(self, exp: u32) -> Self {
253 pow_impl(self, exp)
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use const_num_traits::PrimBits;
261
262 type U16 = FixedUInt<u8, 2, Nct>;
263
264 c0nst::c0nst! {
273 pub c0nst fn const_count_ones<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
274 PrimBits::count_ones(v)
275 }
276 pub c0nst fn const_count_zeros<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
277 PrimBits::count_zeros(v)
278 }
279 pub c0nst fn const_leading_zeros<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
280 PrimBits::leading_zeros(v)
281 }
282 pub c0nst fn const_trailing_zeros<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
283 PrimBits::trailing_zeros(v)
284 }
285 pub c0nst fn const_swap_bytes<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
286 PrimBits::swap_bytes(v)
287 }
288 pub c0nst fn const_rotate_left<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
289 PrimBits::rotate_left(v, n)
290 }
291 pub c0nst fn const_rotate_right<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
292 PrimBits::rotate_right(v, n)
293 }
294 pub c0nst fn const_unsigned_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
295 PrimBits::unsigned_shl(v, n)
296 }
297 pub c0nst fn const_unsigned_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
298 PrimBits::unsigned_shr(v, n)
299 }
300 pub c0nst fn const_signed_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
301 PrimBits::signed_shl(v, n)
302 }
303 pub c0nst fn const_signed_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
304 PrimBits::signed_shr(v, n)
305 }
306 pub c0nst fn const_reverse_bits<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
307 PrimBits::reverse_bits(v)
308 }
309 pub c0nst fn const_to_be<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
310 PrimBits::to_be(v)
311 }
312 pub c0nst fn const_to_le<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
313 PrimBits::to_le(v)
314 }
315 pub c0nst fn const_from_be<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
316 PrimBits::from_be(v)
317 }
318 pub c0nst fn const_from_le<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
319 PrimBits::from_le(v)
320 }
321 }
322
323 #[test]
324 fn nightly_const_eval_prim_bits() {
325 let v = U16::from(0b0010_1000u8);
327 assert_eq!(const_count_ones(v), 2);
328 assert_eq!(const_leading_zeros(v), 10);
329 assert_eq!(const_trailing_zeros(v), 3);
330
331 #[cfg(feature = "nightly")]
332 {
333 const V: U16 = FixedUInt::from_array([0x28, 0]);
334 const V_FULL: U16 = FixedUInt::from_array([0xFF, 0xFF]);
335 const V_ONE: U16 = FixedUInt::from_array([1, 0]);
336
337 const C_ONES: u32 = const_count_ones(V);
338 const C_ZEROS: u32 = const_count_zeros(V);
339 const LZ: u32 = const_leading_zeros(V);
340 const TZ: u32 = const_trailing_zeros(V);
341 const SWAP: U16 = const_swap_bytes(V_ONE);
342 const ROTL: U16 = const_rotate_left(V_ONE, 4);
343 const ROTR: U16 = const_rotate_right(V_ONE, 4);
344 const USHL: U16 = const_unsigned_shl(V_ONE, 4);
345 const USHR: U16 = const_unsigned_shr(V_FULL, 4);
346 const SSHL: U16 = const_signed_shl(V_ONE, 4);
347 const SSHR: U16 = const_signed_shr(V_FULL, 4);
348 const REV: U16 = const_reverse_bits(V_ONE);
349 const TO_BE: U16 = const_to_be(V_ONE);
350 const TO_LE: U16 = const_to_le(V_ONE);
351 const FROM_BE: U16 = const_from_be(V_ONE);
352 const FROM_LE: U16 = const_from_le(V_ONE);
353
354 assert_eq!(C_ONES, 2);
355 assert_eq!(C_ZEROS, 14);
356 assert_eq!(LZ, 10);
357 assert_eq!(TZ, 3);
358 assert_eq!(SWAP.array, [0, 1]);
359 assert_eq!(ROTL.array, [16, 0]);
360 assert_eq!(ROTR.array, [0, 0x10]);
361 assert_eq!(USHL.array, [16, 0]);
362 assert_eq!(USHR.array, [0xFF, 0x0F]);
363 assert_eq!(SSHL.array, [16, 0]);
364 assert_eq!(SSHR.array, [0xFF, 0xFF]);
367 assert_eq!(REV.array, [0, 0x80]);
368 assert_eq!(TO_BE.array, [0, 1]);
369 assert_eq!(TO_LE.array, [1, 0]);
370 assert_eq!(FROM_BE.array, [0, 1]);
371 assert_eq!(FROM_LE.array, [1, 0]);
372 }
373 }
374
375 #[test]
378 fn nightly_const_eval_pow() {
379 let v = U16::from(2u8);
381 assert_eq!(super::pow_impl(v, 8), U16::from(256u16));
382 assert_eq!(super::pow_impl(v, 0), U16::from(1u8));
383
384 #[cfg(feature = "nightly")]
385 {
386 const TWO: U16 = FixedUInt::from_array([2, 0]);
387 const THREE: U16 = FixedUInt::from_array([3, 0]);
388 const TWO_TO_THE_EIGHT: U16 = super::pow_impl(TWO, 8);
389 const THREE_TO_THE_FIVE: U16 = super::pow_impl(THREE, 5);
390 const ZERO_EXP: U16 = super::pow_impl(TWO, 0);
391 assert_eq!(TWO_TO_THE_EIGHT, FixedUInt::from_array([0, 1])); assert_eq!(THREE_TO_THE_FIVE, FixedUInt::from_array([243, 0]));
393 assert_eq!(ZERO_EXP, FixedUInt::from_array([1, 0]));
394 }
395 }
396}