c2rust_bitfields/
lib.rs

1#![cfg_attr(feature = "no_std", no_std)]
2
3pub use c2rust_bitfields_derive::BitfieldStruct;
4
5pub trait FieldType: Sized {
6    const IS_SIGNED: bool;
7
8    #[cfg(not(feature = "no_std"))]
9    const TOTAL_BIT_SIZE: usize = ::std::mem::size_of::<Self>() * 8;
10    #[cfg(feature = "no_std")]
11    const TOTAL_BIT_SIZE: usize = ::core::mem::size_of::<Self>() * 8;
12
13    fn get_bit(&self, bit: usize) -> bool;
14
15    fn set_field(&self, field: &mut [u8], bit_range: (usize, usize)) {
16        fn zero_bit(byte: &mut u8, n_bit: u64) {
17            let bit = 1 << n_bit;
18
19            *byte &= !bit as u8;
20        }
21
22        fn one_bit(byte: &mut u8, n_bit: u64) {
23            let bit = 1 << n_bit;
24
25            *byte |= bit as u8;
26        }
27
28        let (lhs_bit, rhs_bit) = bit_range;
29
30        for (i, bit_index) in (lhs_bit..=rhs_bit).enumerate() {
31            let byte_index = bit_index / 8;
32            let byte = &mut field[byte_index];
33
34            if self.get_bit(i) {
35                one_bit(byte, (bit_index % 8) as u64);
36            } else {
37                zero_bit(byte, (bit_index % 8) as u64);
38            }
39        }
40    }
41
42    fn get_field(field: &[u8], bit_range: (usize, usize)) -> Self;
43}
44
45macro_rules! impl_int {
46    ($($typ: ident),+) => {
47        $(
48            impl FieldType for $typ {
49                const IS_SIGNED: bool = $typ::MIN != 0;
50
51                fn get_bit(&self, bit: usize) -> bool {
52                    ((*self >> bit) & 1) == 1
53                }
54
55                fn get_field(field: &[u8], bit_range: (usize, usize)) -> Self {
56                    let (lhs_bit, rhs_bit) = bit_range;
57                    let mut val = 0;
58
59                    for (i, bit_index) in (lhs_bit..=rhs_bit).enumerate() {
60                        let byte_index = bit_index / 8;
61                        let byte = field[byte_index];
62                        let bit = 1 << (bit_index % 8);
63                        let read_bit = byte & bit;
64
65                        if read_bit != 0 {
66                            let write_bit = 1 << i;
67
68                            val |= write_bit;
69                        }
70                    }
71
72                    // If the int type is signed, sign extend unconditionally
73                    if Self::IS_SIGNED {
74                        let bit_width = rhs_bit - lhs_bit + 1;
75                        let unused_bits = Self::TOTAL_BIT_SIZE - bit_width;
76
77                        val <<= unused_bits;
78                        val >>= unused_bits;
79                    }
80
81                    val
82                }
83            }
84        )+
85    };
86}
87
88impl_int! {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128}
89
90impl FieldType for bool {
91    const IS_SIGNED: bool = false;
92
93    fn get_bit(&self, _bit: usize) -> bool {
94        *self
95    }
96
97    fn get_field(field: &[u8], bit_range: (usize, usize)) -> Self {
98        let (lhs_bit, rhs_bit) = bit_range;
99        let mut val = false;
100
101        for bit_index in lhs_bit..=rhs_bit {
102            let byte_index = bit_index / 8;
103            let byte = field[byte_index];
104            let bit = 1 << (bit_index % 8);
105            let read_bit = byte & bit;
106
107            if read_bit != 0 {
108                val = true;
109            }
110        }
111
112        val
113    }
114}