network_types/
bitfield.rs

1//! A Rust bitfield implementation, copied from
2//! [bindgen](https://github.com/rust-lang/rust-bindgen/blob/master/bindgen/codegen/bitfield_unit.rs)
3//! which is licensed under the
4//! [BSD 3-Clause license](https://github.com/rust-lang/rust-bindgen/blob/master/LICENSE).
5
6#[repr(C)]
7#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct BitfieldUnit<Storage> {
9    storage: Storage,
10}
11
12impl<Storage> BitfieldUnit<Storage> {
13    #[inline]
14    pub const fn new(storage: Storage) -> Self {
15        Self { storage }
16    }
17}
18
19impl<Storage> BitfieldUnit<Storage>
20where
21    Storage: AsRef<[u8]> + AsMut<[u8]>,
22{
23    #[inline]
24    pub fn get_bit(&self, index: usize) -> bool {
25        debug_assert!(index / 8 < self.storage.as_ref().len());
26
27        let byte_index = index / 8;
28        let byte = self.storage.as_ref()[byte_index];
29
30        let bit_index = if cfg!(target_endian = "big") {
31            7 - (index % 8)
32        } else {
33            index % 8
34        };
35
36        let mask = 1 << bit_index;
37
38        byte & mask == mask
39    }
40
41    #[inline]
42    pub fn set_bit(&mut self, index: usize, val: bool) {
43        debug_assert!(index / 8 < self.storage.as_ref().len());
44
45        let byte_index = index / 8;
46        let byte = &mut self.storage.as_mut()[byte_index];
47
48        let bit_index = if cfg!(target_endian = "big") {
49            7 - (index % 8)
50        } else {
51            index % 8
52        };
53
54        let mask = 1 << bit_index;
55        if val {
56            *byte |= mask;
57        } else {
58            *byte &= !mask;
59        }
60    }
61
62    #[inline]
63    pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
64        debug_assert!(bit_width <= 64);
65        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
66        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
67
68        let mut val = 0;
69
70        for i in 0..(bit_width as usize) {
71            if self.get_bit(i + bit_offset) {
72                let index = if cfg!(target_endian = "big") {
73                    bit_width as usize - 1 - i
74                } else {
75                    i
76                };
77                val |= 1 << index;
78            }
79        }
80
81        val
82    }
83
84    #[inline]
85    pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
86        debug_assert!(bit_width <= 64);
87        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
88        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
89
90        for i in 0..(bit_width as usize) {
91            let mask = 1 << i;
92            let val_bit_is_set = val & mask == mask;
93            let index = if cfg!(target_endian = "big") {
94                bit_width as usize - 1 - i
95            } else {
96                i
97            };
98            self.set_bit(index + bit_offset, val_bit_is_set);
99        }
100    }
101}