bitops/
lib.rs

1//! Miscellaneous bit operations for any [`Integer`].
2//!
3//! See the [`BitOps`] trait for examples.
4//!
5//! [`Integer`]: ../num_integer/trait.Integer.html
6//! [`BitOps`]: ./trait.BitOps.html
7
8extern crate num_integer;
9
10use num_integer::Integer;
11use std::ops::{BitAnd, Shl, Shr};
12
13/// Miscellaneous bit operations for any [`Integer`].
14///
15/// # Examples
16///
17/// ```
18/// use bitops::BitOps;
19///
20/// let x = 0b1010_1011_0000_1100; // 0xab0c
21/// let flag = 0b1000;
22///
23/// assert!(flag.is_flag());
24/// assert!(flag.is_bit_set(3));
25///
26/// assert!(x.is_flag_set(flag));
27/// assert_eq!(x.bits_as_int(8, 4), 0xb);
28/// ```
29///
30/// [`Integer`]: ../num_integer/trait.Integer.html
31pub trait BitOps:
32    Copy + Integer + BitAnd<Output = Self> + Shl<Output = Self> + Shr<Output = Self> + From<u8>
33{
34    /// Returns whether this number only has one bit set.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use bitops::BitOps;
40    ///
41    /// assert!(0b1000.is_flag());
42    /// assert!(!0b1001.is_flag());
43    /// ```
44    #[inline]
45    fn is_flag(&self) -> bool {
46        *self > Self::zero() && (*self & (*self - Self::one())) == Self::zero()
47    }
48
49    /// Returns whether the given bit number is set.
50    ///
51    /// # Panics
52    ///
53    /// Panics if `bit` is greater than the number of bits in this Integer.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use bitops::BitOps;
59    ///
60    /// assert!(0b1000.is_bit_set(3));
61    /// ```
62    #[inline]
63    fn is_bit_set(&self, bit: u8) -> bool {
64        self.is_flag_set(Self::one() << Self::from(bit))
65    }
66
67    /// Returns whether the given flag is set.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use bitops::BitOps;
73    ///
74    /// assert!(0b11010.is_flag_set(0b11000));
75    /// ```
76    #[inline]
77    fn is_flag_set(&self, flag: Self) -> bool {
78        *self & flag > Self::zero()
79    }
80
81    /// Returns a number with bit 0 starting at the given bit and up to `count` left most bits.
82    /// This is basically a right shift by `bit` and masked with `(1 << count) - 1`.
83    ///
84    /// # Panics
85    ///
86    /// Panics if `bit` is greater than the number of bits in this Integer.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use bitops::BitOps;
92    ///
93    /// assert_eq!(0xab000.bits_as_int(12, 8), 0xab);
94    /// ```
95    #[inline]
96    fn bits_as_int(&self, bit: u8, count: u8) -> Self {
97        (*self >> Self::from(bit)) & ((Self::one() << Self::from(count)) - Self::one())
98    }
99}
100
101/// Implements the [`BitOps`] trait for all types that meet the requirements.
102impl<N> BitOps for N
103where
104    N: Copy + Integer + BitAnd<Output = Self> + Shl<Output = Self> + Shr<Output = Self> + From<u8>,
105{
106}
107
108mod tests {
109    #[allow(unused_imports)]
110    use super::BitOps;
111
112    #[test]
113    fn flag_zero() {
114        assert!(!0.is_flag());
115    }
116
117    #[test]
118    fn flag_set_blank() {
119        assert!(!0x0000.is_flag_set(0));
120    }
121
122    #[test]
123    fn bits_at_zero() {
124        assert_eq!(0xabcd.bits_as_int(0, 8), 0xcd);
125    }
126
127    #[test]
128    #[should_panic]
129    fn bits_overflow() {
130        0u16.bits_as_int(16, 0);
131    }
132}