1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
//! Push and pop the bit-packed fields. //! //! It's common for network protocols to have bit-packed fields //! as a fixed width row in its header. //! Each fields have their own bit width, and its bit offset is defined //! as a sum of the widths of previous fields of the same row. //! //! Traditionaly to set/extract those field one should manage //! both width and offset of the field. //! But since all the fields of this row are handled, //! the offset is a redaundant information we should not care ourselves. //! //! That's where the pushbits came from. //! This crate provides fixed width bit container where you can //! push and pop the bits as a integer using bitshift left operation. //! If the widths are constant, the compiler optimize out all the overheads. /// 32bits container where you can push and pop multiple bits as a integer. /// /// See the crate level documentaion for more details. #[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Bits32 { bits: u32, } impl Bits32 { /// Bit width of this container. pub const BIT_WIDTH: u32 = 32; /// Create a new Bits32 container with the given bit pattern. #[inline] pub fn new(bits: u32) -> Self { Bits32 { bits } } /// Copy out the current bit pattern of this container. /// /// # Example /// /// ``` /// # use pushbits::Bits32; /// let mut bits = Bits32::new(0); /// bits.push(5, 0b10110_u16); /// bits.push_bool(true); /// assert_eq!(0b10110_1, bits.get()); /// ``` #[inline] pub fn get(&self) -> u32 { self.bits } /// Push given number of bits into the LSB of this container /// using the bit shift left operation. /// /// # Panics /// /// It panics if the `num_bits` is greater than 31. /// /// # Examples /// /// ``` /// # use pushbits::Bits32; /// let mut bits = Bits32::new(0); /// bits.push(8, 0b11100110_u32); /// bits.push(5, 0b10001_u8); /// assert_eq!(0b11100110_10001, bits.get()); /// ``` #[inline] pub fn push<T: Into<u32>>(&mut self, num_bits: u32, value: T) { assert!(num_bits < Self::BIT_WIDTH); self.bits <<= num_bits; let mask = (1 << num_bits) - 1; let value = value.into() & mask; self.bits |= value; } /// Push a boolean as a single bit. /// /// # Examples /// /// ``` /// # use pushbits::Bits32; /// let mut bits = Bits32::new(0); /// bits.push_bool(true); /// bits.push_bool(false); /// assert_eq!(0b10, bits.get()); /// ``` #[inline] pub fn push_bool(&mut self, value: bool) { self.push(1, value) } /// Pop given number of bits out from the MSB of this container /// using the bit shift left operation. /// /// # Panics /// /// It panics if the `num_bits` is greater than 31. /// /// # Examples /// /// ``` /// # use pushbits::Bits32; /// let mut bits = Bits32::new(0xDEADBEEF); /// assert_eq!(0xDEA, bits.pop(12)); /// assert_eq!(0xDBE, bits.pop(12)); /// assert_eq!(0xEF, bits.pop(8)); /// ``` #[inline] pub fn pop(&mut self, num_bits: u32) -> u32 { assert!(num_bits < Self::BIT_WIDTH); let res = self.bits >> (Self::BIT_WIDTH - num_bits); self.bits <<= num_bits; res } /// Pop a single bit out as a boolean. /// /// # Examples /// /// ``` /// # use pushbits::Bits32; /// let mut bits = Bits32::new(0b101); /// bits.push(Bits32::BIT_WIDTH - 3, 0_u32); /// assert_eq!(true, bits.pop_bool()); /// assert_eq!(false, bits.pop_bool()); /// assert_eq!(true, bits.pop_bool()); /// ``` #[inline] pub fn pop_bool(&mut self) -> bool { self.pop(1) != 0 } }