Skip to main content

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}