Skip to content

Commit 01e096b

Browse files
committed
Add additional helpers to bitmask data structure
This commit addresses the case where a struct containing a bitfield is wrapped in a struct such as UnsafeCell which allows interior mutability. Previously, bitfield accessors only allowed a receiver. This becomes problematic in the case of interior mutability as raw pointer access may be required so as not to violate the aliasing rules in Rust.
1 parent 66b6551 commit 01e096b

File tree

3 files changed

+136
-10
lines changed

3 files changed

+136
-10
lines changed

bindgen/codegen/.bitfield_unit.rs.swp

16 KB
Binary file not shown.

bindgen/codegen/bitfield_unit.rs

+97-10
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ where
1616
Storage: AsRef<[u8]> + AsMut<[u8]>,
1717
{
1818
#[inline]
19-
pub fn get_bit(&self, index: usize) -> bool {
20-
debug_assert!(index / 8 < self.storage.as_ref().len());
21-
22-
let byte_index = index / 8;
23-
let byte = self.storage.as_ref()[byte_index];
24-
19+
fn extract_bit(byte: u8, index: usize) -> bool {
2520
let bit_index = if cfg!(target_endian = "big") {
2621
7 - (index % 8)
2722
} else {
@@ -34,12 +29,28 @@ where
3429
}
3530

3631
#[inline]
37-
pub fn set_bit(&mut self, index: usize, val: bool) {
32+
pub fn get_bit(&self, index: usize) -> bool {
3833
debug_assert!(index / 8 < self.storage.as_ref().len());
3934

4035
let byte_index = index / 8;
41-
let byte = &mut self.storage.as_mut()[byte_index];
36+
let byte = self.storage.as_ref()[byte_index];
37+
38+
Self::extract_bit(byte, index)
39+
}
40+
41+
#[inline]
42+
pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool {
43+
debug_assert!(index / 8 < std::mem::size_of::<Storage>());
44+
45+
let byte_index = index / 8;
46+
let byte = *(std::ptr::addr_of!((*this).storage) as *const u8)
47+
.offset(byte_index as isize);
48+
49+
Self::extract_bit(byte, index)
50+
}
4251

52+
#[inline]
53+
fn change_bit(byte: u8, index: usize, val: bool) -> u8 {
4354
let bit_index = if cfg!(target_endian = "big") {
4455
7 - (index % 8)
4556
} else {
@@ -48,12 +59,33 @@ where
4859

4960
let mask = 1 << bit_index;
5061
if val {
51-
*byte |= mask;
62+
byte | mask
5263
} else {
53-
*byte &= !mask;
64+
byte & !mask
5465
}
5566
}
5667

68+
#[inline]
69+
pub fn set_bit(&mut self, index: usize, val: bool) {
70+
debug_assert!(index / 8 < self.storage.as_ref().len());
71+
72+
let byte_index = index / 8;
73+
let byte = &mut self.storage.as_mut()[byte_index];
74+
75+
*byte = Self::change_bit(*byte, index, val);
76+
}
77+
78+
#[inline]
79+
pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) {
80+
debug_assert!(index / 8 < std::mem::size_of::<Storage>());
81+
82+
let byte_index = index / 8;
83+
let byte = (std::ptr::addr_of_mut!((*this).storage) as *mut u8)
84+
.offset(byte_index as isize);
85+
86+
*byte = Self::change_bit(*byte, index, val);
87+
}
88+
5789
#[inline]
5890
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
5991
debug_assert!(bit_width <= 64);
@@ -79,6 +111,35 @@ where
79111
val
80112
}
81113

114+
#[inline]
115+
pub unsafe fn raw_get(
116+
this: *const Self,
117+
bit_offset: usize,
118+
bit_width: u8,
119+
) -> u64 {
120+
debug_assert!(bit_width <= 64);
121+
debug_assert!(bit_offset / 8 < std::mem::size_of::<Storage>());
122+
debug_assert!(
123+
(bit_offset + (bit_width as usize)) / 8 <=
124+
std::mem::size_of::<Storage>()
125+
);
126+
127+
let mut val = 0;
128+
129+
for i in 0..(bit_width as usize) {
130+
if Self::raw_get_bit(this, i + bit_offset) {
131+
let index = if cfg!(target_endian = "big") {
132+
bit_width as usize - 1 - i
133+
} else {
134+
i
135+
};
136+
val |= 1 << index;
137+
}
138+
}
139+
140+
val
141+
}
142+
82143
#[inline]
83144
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
84145
debug_assert!(bit_width <= 64);
@@ -99,4 +160,30 @@ where
99160
self.set_bit(index + bit_offset, val_bit_is_set);
100161
}
101162
}
163+
164+
#[inline]
165+
pub unsafe fn raw_set(
166+
this: *mut Self,
167+
bit_offset: usize,
168+
bit_width: u8,
169+
val: u64,
170+
) {
171+
debug_assert!(bit_width <= 64);
172+
debug_assert!(bit_offset / 8 < std::mem::size_of::<Storage>());
173+
debug_assert!(
174+
(bit_offset + (bit_width as usize)) / 8 <=
175+
std::mem::size_of::<Storage>()
176+
);
177+
178+
for i in 0..(bit_width as usize) {
179+
let mask = 1 << i;
180+
let val_bit_is_set = val & mask == mask;
181+
let index = if cfg!(target_endian = "big") {
182+
bit_width as usize - 1 - i
183+
} else {
184+
i
185+
};
186+
Self::raw_set_bit(this, index + bit_offset, val_bit_is_set);
187+
}
188+
}
102189
}

bindgen/codegen/mod.rs

+39
Original file line numberDiff line numberDiff line change
@@ -1849,6 +1849,15 @@ fn bitfield_getter_name(
18491849
quote! { #name }
18501850
}
18511851

1852+
fn bitfield_raw_getter_name(
1853+
ctx: &BindgenContext,
1854+
bitfield: &Bitfield,
1855+
) -> proc_macro2::TokenStream {
1856+
let name = bitfield.getter_name();
1857+
let name = ctx.rust_ident_raw(format!("raw_{name}"));
1858+
quote! { #name }
1859+
}
1860+
18521861
fn bitfield_setter_name(
18531862
ctx: &BindgenContext,
18541863
bitfield: &Bitfield,
@@ -1858,6 +1867,15 @@ fn bitfield_setter_name(
18581867
quote! { #setter }
18591868
}
18601869

1870+
fn bitfield_raw_setter_name(
1871+
ctx: &BindgenContext,
1872+
bitfield: &Bitfield,
1873+
) -> proc_macro2::TokenStream {
1874+
let setter = bitfield.setter_name();
1875+
let setter = ctx.rust_ident_raw(format!("raw_{setter}"));
1876+
quote! { #setter }
1877+
}
1878+
18611879
impl<'a> FieldCodegen<'a> for Bitfield {
18621880
type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind);
18631881

@@ -1885,6 +1903,8 @@ impl<'a> FieldCodegen<'a> for Bitfield {
18851903
let prefix = ctx.trait_prefix();
18861904
let getter_name = bitfield_getter_name(ctx, self);
18871905
let setter_name = bitfield_setter_name(ctx, self);
1906+
let raw_getter_name = bitfield_raw_getter_name(ctx, self);
1907+
let raw_setter_name = bitfield_raw_setter_name(ctx, self);
18881908
let unit_field_ident = Ident::new(unit_field_name, Span::call_site());
18891909

18901910
let bitfield_ty_item = ctx.resolve_item(self.ty());
@@ -1951,6 +1971,25 @@ impl<'a> FieldCodegen<'a> for Bitfield {
19511971
)
19521972
}
19531973
}
1974+
1975+
#[inline]
1976+
#access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty {
1977+
unsafe {
1978+
::std::mem::transmute(__BindgenBitfieldUnit::raw_get(
1979+
addr_of!((*this).#unit_field_ident),
1980+
#offset,
1981+
#width,
1982+
) as #bitfield_int_ty)
1983+
}
1984+
}
1985+
1986+
#[inline]
1987+
#access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) {
1988+
unsafe {
1989+
let val: #bitfield_int_ty = ::std::mem::transmute(val);
1990+
__BindgenBitfieldUnit::raw_set(addr_of!((*this)._bitfield_1), #offset, #width, val as u64)
1991+
}
1992+
}
19541993
}));
19551994
} else {
19561995
methods.extend(Some(quote! {

0 commit comments

Comments
 (0)