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
    }
}