const_num_traits/int.rs
1use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
2
3use crate::bounds::Bounded;
4use crate::identities::{ConstOne, ConstZero};
5use crate::ops::checked::*;
6use crate::ops::saturating::Saturating;
7use crate::{Num, NumCast};
8
9c0nst::c0nst! {
10/// Bit-level operations on fixed-width binary integers.
11///
12/// This is the capability-pure core extracted from [`PrimInt`]: bit
13/// counting, rotations, shifts, byte/bit reversal and endianness
14/// conversions. It deliberately requires **no comparison** (`Ord`,
15/// `PartialEq`) and **no arithmetic** (`Add`/`Mul`/`Div`), so it is
16/// implementable by constant-time integer types that expose only bit
17/// operations (every method here is branchless on the operand for the
18/// builtin integers).
19///
20/// The only non-bit requirement is the `ZERO`/`ONE` *constants* that the
21/// bit-twiddling defaults need. These come from [`ConstZero`]/[`ConstOne`],
22/// which are deliberately decoupled from [`Zero`](crate::Zero)/[`One`](crate::One)
23/// — they carry the compile-time constant **without** pulling in `Add`/`Mul`.
24/// So a type can implement `PrimBits` with bit ops and two constants alone.
25///
26/// [`ConstZero`]: crate::ConstZero
27/// [`ConstOne`]: crate::ConstOne
28pub c0nst trait PrimBits:
29 Sized
30 + Copy
31 + ConstZero
32 + ConstOne
33 + [c0nst] Not<Output = Self>
34 + [c0nst] BitAnd<Output = Self>
35 + [c0nst] BitOr<Output = Self>
36 + [c0nst] BitXor<Output = Self>
37 + [c0nst] Shl<usize, Output = Self>
38 + [c0nst] Shr<usize, Output = Self>
39{
40 /// Returns the number of ones in the binary representation of `self`.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use const_num_traits::PrimBits;
46 ///
47 /// let n = 0b01001100u8;
48 ///
49 /// assert_eq!(n.count_ones(), 3);
50 /// ```
51 fn count_ones(self) -> u32;
52
53 /// Returns the number of zeros in the binary representation of `self`.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use const_num_traits::PrimBits;
59 ///
60 /// let n = 0b01001100u8;
61 ///
62 /// assert_eq!(n.count_zeros(), 5);
63 /// ```
64 fn count_zeros(self) -> u32;
65
66 /// Returns the number of leading ones in the binary representation
67 /// of `self`.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use const_num_traits::PrimBits;
73 ///
74 /// let n = 0xF00Du16;
75 ///
76 /// assert_eq!(n.leading_ones(), 4);
77 /// ```
78 fn leading_ones(self) -> u32 {
79 (!self).leading_zeros()
80 }
81
82 /// Returns the number of leading zeros in the binary representation
83 /// of `self`.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use const_num_traits::PrimBits;
89 ///
90 /// let n = 0b0101000u16;
91 ///
92 /// assert_eq!(n.leading_zeros(), 10);
93 /// ```
94 fn leading_zeros(self) -> u32;
95
96 /// Returns the number of trailing ones in the binary representation
97 /// of `self`.
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use const_num_traits::PrimBits;
103 ///
104 /// let n = 0xBEEFu16;
105 ///
106 /// assert_eq!(n.trailing_ones(), 4);
107 /// ```
108 fn trailing_ones(self) -> u32 {
109 (!self).trailing_zeros()
110 }
111
112 /// Returns the number of trailing zeros in the binary representation
113 /// of `self`.
114 ///
115 /// # Examples
116 ///
117 /// ```
118 /// use const_num_traits::PrimBits;
119 ///
120 /// let n = 0b0101000u16;
121 ///
122 /// assert_eq!(n.trailing_zeros(), 3);
123 /// ```
124 fn trailing_zeros(self) -> u32;
125
126 /// Shifts the bits to the left by a specified amount, `n`, wrapping
127 /// the truncated bits to the end of the resulting integer.
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// use const_num_traits::PrimBits;
133 ///
134 /// let n = 0x0123456789ABCDEFu64;
135 /// let m = 0x3456789ABCDEF012u64;
136 ///
137 /// assert_eq!(n.rotate_left(12), m);
138 /// ```
139 fn rotate_left(self, n: u32) -> Self;
140
141 /// Shifts the bits to the right by a specified amount, `n`, wrapping
142 /// the truncated bits to the beginning of the resulting integer.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use const_num_traits::PrimBits;
148 ///
149 /// let n = 0x0123456789ABCDEFu64;
150 /// let m = 0xDEF0123456789ABCu64;
151 ///
152 /// assert_eq!(n.rotate_right(12), m);
153 /// ```
154 fn rotate_right(self, n: u32) -> Self;
155
156 /// Shifts the bits to the left by a specified amount, `n`, filling
157 /// zeros in the least significant bits.
158 ///
159 /// This is bitwise equivalent to signed `Shl`.
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// use const_num_traits::PrimBits;
165 ///
166 /// let n = 0x0123456789ABCDEFu64;
167 /// let m = 0x3456789ABCDEF000u64;
168 ///
169 /// assert_eq!(n.signed_shl(12), m);
170 /// ```
171 fn signed_shl(self, n: u32) -> Self;
172
173 /// Shifts the bits to the right by a specified amount, `n`, copying
174 /// the "sign bit" in the most significant bits even for unsigned types.
175 ///
176 /// This is bitwise equivalent to signed `Shr`.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use const_num_traits::PrimBits;
182 ///
183 /// let n = 0xFEDCBA9876543210u64;
184 /// let m = 0xFFFFEDCBA9876543u64;
185 ///
186 /// assert_eq!(n.signed_shr(12), m);
187 /// ```
188 fn signed_shr(self, n: u32) -> Self;
189
190 /// Shifts the bits to the left by a specified amount, `n`, filling
191 /// zeros in the least significant bits.
192 ///
193 /// This is bitwise equivalent to unsigned `Shl`.
194 ///
195 /// # Examples
196 ///
197 /// ```
198 /// use const_num_traits::PrimBits;
199 ///
200 /// let n = 0x0123456789ABCDEFi64;
201 /// let m = 0x3456789ABCDEF000i64;
202 ///
203 /// assert_eq!(n.unsigned_shl(12), m);
204 /// ```
205 fn unsigned_shl(self, n: u32) -> Self;
206
207 /// Shifts the bits to the right by a specified amount, `n`, filling
208 /// zeros in the most significant bits.
209 ///
210 /// This is bitwise equivalent to unsigned `Shr`.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use const_num_traits::PrimBits;
216 ///
217 /// let n = -8i8; // 0b11111000
218 /// let m = 62i8; // 0b00111110
219 ///
220 /// assert_eq!(n.unsigned_shr(2), m);
221 /// ```
222 fn unsigned_shr(self, n: u32) -> Self;
223
224 /// Reverses the byte order of the integer.
225 ///
226 /// # Examples
227 ///
228 /// ```
229 /// use const_num_traits::PrimBits;
230 ///
231 /// let n = 0x0123456789ABCDEFu64;
232 /// let m = 0xEFCDAB8967452301u64;
233 ///
234 /// assert_eq!(n.swap_bytes(), m);
235 /// ```
236 fn swap_bytes(self) -> Self;
237
238 /// Reverses the order of bits in the integer.
239 ///
240 /// The least significant bit becomes the most significant bit, second least-significant bit
241 /// becomes second most-significant bit, etc.
242 ///
243 /// # Examples
244 ///
245 /// ```
246 /// use const_num_traits::PrimBits;
247 ///
248 /// let n = 0x12345678u32;
249 /// let m = 0x1e6a2c48u32;
250 ///
251 /// assert_eq!(n.reverse_bits(), m);
252 /// assert_eq!(0u32.reverse_bits(), 0);
253 /// ```
254 fn reverse_bits(self) -> Self {
255 reverse_bits_fallback(self)
256 }
257
258 /// Convert an integer from big endian to the target's endianness.
259 ///
260 /// On big endian this is a no-op. On little endian the bytes are swapped.
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// use const_num_traits::PrimBits;
266 ///
267 /// let n = 0x0123456789ABCDEFu64;
268 ///
269 /// if cfg!(target_endian = "big") {
270 /// assert_eq!(u64::from_be(n), n)
271 /// } else {
272 /// assert_eq!(u64::from_be(n), n.swap_bytes())
273 /// }
274 /// ```
275 fn from_be(x: Self) -> Self;
276
277 /// Convert an integer from little endian to the target's endianness.
278 ///
279 /// On little endian this is a no-op. On big endian the bytes are swapped.
280 ///
281 /// # Examples
282 ///
283 /// ```
284 /// use const_num_traits::PrimBits;
285 ///
286 /// let n = 0x0123456789ABCDEFu64;
287 ///
288 /// if cfg!(target_endian = "little") {
289 /// assert_eq!(u64::from_le(n), n)
290 /// } else {
291 /// assert_eq!(u64::from_le(n), n.swap_bytes())
292 /// }
293 /// ```
294 fn from_le(x: Self) -> Self;
295
296 /// Convert `self` to big endian from the target's endianness.
297 ///
298 /// On big endian this is a no-op. On little endian the bytes are swapped.
299 ///
300 /// # Examples
301 ///
302 /// ```
303 /// use const_num_traits::PrimBits;
304 ///
305 /// let n = 0x0123456789ABCDEFu64;
306 ///
307 /// if cfg!(target_endian = "big") {
308 /// assert_eq!(n.to_be(), n)
309 /// } else {
310 /// assert_eq!(n.to_be(), n.swap_bytes())
311 /// }
312 /// ```
313 fn to_be(self) -> Self;
314
315 /// Convert `self` to little endian from the target's endianness.
316 ///
317 /// On little endian this is a no-op. On big endian the bytes are swapped.
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// use const_num_traits::PrimBits;
323 ///
324 /// let n = 0x0123456789ABCDEFu64;
325 ///
326 /// if cfg!(target_endian = "little") {
327 /// assert_eq!(n.to_le(), n)
328 /// } else {
329 /// assert_eq!(n.to_le(), n.swap_bytes())
330 /// }
331 /// ```
332 fn to_le(self) -> Self;
333}
334}
335
336c0nst::c0nst! {
337/// Generic trait for primitive integers.
338///
339/// The `PrimInt` trait is an abstraction over the builtin primitive integer types (e.g., `u8`,
340/// `u32`, `isize`, `i128`, ...). It inherits the basic numeric traits and extends them with
341/// bitwise operators and non-wrapping arithmetic.
342///
343/// The trait explicitly inherits `Copy`, `Eq`, `Ord`, and `Sized`. The intention is that all
344/// types implementing this trait behave like primitive types that are passed by value by default
345/// and behave like builtin integers. Furthermore, the types are expected to expose the integer
346/// value in binary representation and support bitwise operators. The standard bitwise operations
347/// (e.g., bitwise-and, bitwise-or, right-shift, left-shift) are inherited, and the bit-level
348/// introspection methods (e.g., `count_ones()`, `leading_zeros()`), bitwise combinators (e.g.,
349/// `rotate_left()`), and endianness converters (e.g., `to_be()`) come from the [`PrimBits`]
350/// supertrait.
351///
352/// All `PrimInt` types are expected to be fixed-width binary integers. The width can be queried
353/// via `T::zero().count_zeros()`. The trait currently lacks a way to query the width at
354/// compile-time.
355///
356/// While a default implementation for all builtin primitive integers is provided, the trait is in
357/// no way restricted to these. Other integer types that fulfil the requirements are free to
358/// implement the trait was well.
359///
360/// Types that cannot expose comparison or division (e.g. constant-time
361/// integers) should implement only [`PrimBits`]; `PrimInt` adds the
362/// `Ord`/`Num`/checked-arithmetic capabilities on top.
363///
364/// This trait and many of the method names originate in the unstable `core::num::Int` trait from
365/// the rust standard library. The original trait was never stabilized and thus removed from the
366/// standard library.
367pub c0nst trait PrimInt:
368 Sized
369 + Copy
370 + [c0nst] PrimBits
371 + [c0nst] Num
372 + [c0nst] NumCast
373 + [c0nst] Bounded
374 + [c0nst] PartialOrd
375 + [c0nst] Ord
376 + [c0nst] Eq
377 + [c0nst] CheckedAdd<Output = Self>
378 + [c0nst] CheckedSub<Output = Self>
379 + [c0nst] CheckedMul<Output = Self>
380 + [c0nst] CheckedDiv<Output = Self>
381 + [c0nst] Saturating
382{
383 /// Raises self to the power of `exp`, using exponentiation by squaring.
384 ///
385 /// # Examples
386 ///
387 /// ```
388 /// use const_num_traits::PrimInt;
389 ///
390 /// assert_eq!(2i32.pow(4), 16);
391 /// ```
392 fn pow(self, exp: u32) -> Self;
393}
394}
395
396c0nst::c0nst! {
397c0nst fn one_per_byte<P: [c0nst] PrimBits>() -> P {
398 // i8, u8: return 0x01
399 // i16, u16: return 0x0101 = (0x01 << 8) | 0x01
400 // i32, u32: return 0x01010101 = (0x0101 << 16) | 0x0101
401 // ...
402 let mut ret = P::ONE;
403 let mut shift = 8;
404 let mut b = ret.count_zeros() >> 3;
405 while b != 0 {
406 ret = (ret << shift) | ret;
407 shift <<= 1;
408 b >>= 1;
409 }
410 ret
411}
412}
413
414c0nst::c0nst! {
415c0nst fn reverse_bits_fallback<P: [c0nst] PrimBits>(i: P) -> P {
416 let rep_01: P = one_per_byte();
417 let rep_03 = (rep_01 << 1) | rep_01;
418 let rep_05 = (rep_01 << 2) | rep_01;
419 let rep_0f = (rep_03 << 2) | rep_03;
420 let rep_33 = (rep_03 << 4) | rep_03;
421 let rep_55 = (rep_05 << 4) | rep_05;
422
423 // code above only used to determine rep_0f, rep_33, rep_55;
424 // optimizer should be able to do it in compile time
425 let mut ret = i.swap_bytes();
426 ret = ((ret & rep_0f) << 4) | ((ret >> 4) & rep_0f);
427 ret = ((ret & rep_33) << 2) | ((ret >> 2) & rep_33);
428 ret = ((ret & rep_55) << 1) | ((ret >> 1) & rep_55);
429 ret
430}
431}
432
433macro_rules! prim_int_impl {
434 ($T:ty, $S:ty, $U:ty) => {
435 c0nst::c0nst! {
436 c0nst impl PrimBits for $T {
437 #[inline]
438 fn count_ones(self) -> u32 {
439 <$T>::count_ones(self)
440 }
441
442 #[inline]
443 fn count_zeros(self) -> u32 {
444 <$T>::count_zeros(self)
445 }
446
447 #[inline]
448 fn leading_ones(self) -> u32 {
449 <$T>::leading_ones(self)
450 }
451
452 #[inline]
453 fn leading_zeros(self) -> u32 {
454 <$T>::leading_zeros(self)
455 }
456
457 #[inline]
458 fn trailing_ones(self) -> u32 {
459 <$T>::trailing_ones(self)
460 }
461
462 #[inline]
463 fn trailing_zeros(self) -> u32 {
464 <$T>::trailing_zeros(self)
465 }
466
467 #[inline]
468 fn rotate_left(self, n: u32) -> Self {
469 <$T>::rotate_left(self, n)
470 }
471
472 #[inline]
473 fn rotate_right(self, n: u32) -> Self {
474 <$T>::rotate_right(self, n)
475 }
476
477 #[inline]
478 fn signed_shl(self, n: u32) -> Self {
479 ((self as $S) << n) as $T
480 }
481
482 #[inline]
483 fn signed_shr(self, n: u32) -> Self {
484 ((self as $S) >> n) as $T
485 }
486
487 #[inline]
488 fn unsigned_shl(self, n: u32) -> Self {
489 ((self as $U) << n) as $T
490 }
491
492 #[inline]
493 fn unsigned_shr(self, n: u32) -> Self {
494 ((self as $U) >> n) as $T
495 }
496
497 #[inline]
498 fn swap_bytes(self) -> Self {
499 <$T>::swap_bytes(self)
500 }
501
502 #[inline]
503 fn reverse_bits(self) -> Self {
504 <$T>::reverse_bits(self)
505 }
506
507 #[inline]
508 fn from_be(x: Self) -> Self {
509 <$T>::from_be(x)
510 }
511
512 #[inline]
513 fn from_le(x: Self) -> Self {
514 <$T>::from_le(x)
515 }
516
517 #[inline]
518 fn to_be(self) -> Self {
519 <$T>::to_be(self)
520 }
521
522 #[inline]
523 fn to_le(self) -> Self {
524 <$T>::to_le(self)
525 }
526 }
527 }
528
529 c0nst::c0nst! {
530 c0nst impl PrimInt for $T {
531 #[inline]
532 fn pow(self, exp: u32) -> Self {
533 <$T>::pow(self, exp)
534 }
535 }
536 }
537 };
538}
539
540// prim_int_impl!(type, signed, unsigned);
541prim_int_impl!(u8, i8, u8);
542prim_int_impl!(u16, i16, u16);
543prim_int_impl!(u32, i32, u32);
544prim_int_impl!(u64, i64, u64);
545prim_int_impl!(u128, i128, u128);
546prim_int_impl!(usize, isize, usize);
547prim_int_impl!(i8, i8, u8);
548prim_int_impl!(i16, i16, u16);
549prim_int_impl!(i32, i32, u32);
550prim_int_impl!(i64, i64, u64);
551prim_int_impl!(i128, i128, u128);
552prim_int_impl!(isize, isize, usize);
553
554#[cfg(test)]
555mod tests {
556 use crate::int::PrimBits;
557
558 #[test]
559 pub fn reverse_bits() {
560 assert_eq!(
561 PrimBits::reverse_bits(0x0123_4567_89ab_cdefu64),
562 0xf7b3_d591_e6a2_c480
563 );
564
565 assert_eq!(PrimBits::reverse_bits(0i8), 0);
566 assert_eq!(PrimBits::reverse_bits(-1i8), -1);
567 assert_eq!(PrimBits::reverse_bits(1i8), i8::MIN);
568 assert_eq!(PrimBits::reverse_bits(i8::MIN), 1);
569 assert_eq!(PrimBits::reverse_bits(-2i8), i8::MAX);
570 assert_eq!(PrimBits::reverse_bits(i8::MAX), -2);
571
572 assert_eq!(PrimBits::reverse_bits(0i16), 0);
573 assert_eq!(PrimBits::reverse_bits(-1i16), -1);
574 assert_eq!(PrimBits::reverse_bits(1i16), i16::MIN);
575 assert_eq!(PrimBits::reverse_bits(i16::MIN), 1);
576 assert_eq!(PrimBits::reverse_bits(-2i16), i16::MAX);
577 assert_eq!(PrimBits::reverse_bits(i16::MAX), -2);
578
579 assert_eq!(PrimBits::reverse_bits(0i32), 0);
580 assert_eq!(PrimBits::reverse_bits(-1i32), -1);
581 assert_eq!(PrimBits::reverse_bits(1i32), i32::MIN);
582 assert_eq!(PrimBits::reverse_bits(i32::MIN), 1);
583 assert_eq!(PrimBits::reverse_bits(-2i32), i32::MAX);
584 assert_eq!(PrimBits::reverse_bits(i32::MAX), -2);
585
586 assert_eq!(PrimBits::reverse_bits(0i64), 0);
587 assert_eq!(PrimBits::reverse_bits(-1i64), -1);
588 assert_eq!(PrimBits::reverse_bits(1i64), i64::MIN);
589 assert_eq!(PrimBits::reverse_bits(i64::MIN), 1);
590 assert_eq!(PrimBits::reverse_bits(-2i64), i64::MAX);
591 assert_eq!(PrimBits::reverse_bits(i64::MAX), -2);
592 }
593
594 #[test]
595 pub fn reverse_bits_i128() {
596 assert_eq!(PrimBits::reverse_bits(0i128), 0);
597 assert_eq!(PrimBits::reverse_bits(-1i128), -1);
598 assert_eq!(PrimBits::reverse_bits(1i128), i128::MIN);
599 assert_eq!(PrimBits::reverse_bits(i128::MIN), 1);
600 assert_eq!(PrimBits::reverse_bits(-2i128), i128::MAX);
601 assert_eq!(PrimBits::reverse_bits(i128::MAX), -2);
602 }
603}