diff options
author | Nick Fitzgerald <fitzgen@gmail.com> | 2017-10-25 17:31:21 -0700 |
---|---|---|
committer | Glyn Normington <gnormington@pivotal.io> | 2017-11-21 13:55:00 +0000 |
commit | f0e05310b43e88e541ed011d20994c02fdcc1a3a (patch) | |
tree | be05ee8a3fa1a1d7f696daa630e48a824276ff61 /src/codegen/helpers.rs | |
parent | 5e0cf9c356960e0459fea22cf0754dbec66f58b4 (diff) |
Support bitfield allocation units larger than 64 bits
Individual bitfields are still limited to at most 64 bits, but this
restriction can be weakened when Rust supports u128.
This implements issue #816.
Usage notes:
* Since common code is added to each generated binding, a program which uses
more than one binding may need to work around the duplication by including
each binding in its own module.
* The values created by bitfield allocation unit constructors can be assigned
directly to the corresponding struct fields with no need for transmutation.
Implementation notes:
__BindgenBitfieldUnit represents a bitfield allocation unit using a Storage
type accessible as a slice of u8. The alignment of the unit is inherited from
an Align type by virtue of the field:
align: [Align; 0],
The position of this field in the struct is irrelevant.
The alignment of the Storage type is intended to be no larger than the
alignment of the Align type, which will be true if the Storage type is, for
example, an array of u8.
Although the double underscore (__) prefix is reserved for implementations of
C++, there are precedents for this convention elsewhere in bindgen and so the
convention is adopted here too.
Acknowledgement:
Thanks to @fitzgen for an initial implementation of __BindgenBitfieldUnit and
code to integrate it into bindgen.
Diffstat (limited to 'src/codegen/helpers.rs')
-rw-r--r-- | src/codegen/helpers.rs | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index 4ff398c4..99054305 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -1,7 +1,9 @@ //! Helpers for code generation that don't need macro expansion. +use ir::context::BindgenContext; use ir::layout::Layout; use quote; +use std::mem; pub mod attributes { use quote; @@ -86,6 +88,39 @@ pub fn blob(layout: Layout) -> quote::Tokens { } } +/// Integer type of the same size as the given `Layout`. +pub fn integer_type(layout: Layout) -> Option<quote::Tokens> { + // This guard can be weakened when Rust implements u128. + if layout.size > mem::size_of::<u64>() { + None + } else { + Some(blob(layout)) + } +} + +/// Generates a bitfield allocation unit type for a type with the given `Layout`. +pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> quote::Tokens { + let mut tokens = quote! {}; + + if ctx.options().enable_cxx_namespaces { + tokens.append(quote! { root:: }); + } + + let align = match layout.align { + n if n >= 8 => quote! { u64 }, + 4 => quote! { u32 }, + 2 => quote! { u16 }, + _ => quote! { u8 }, + }; + + let size = layout.size; + tokens.append(quote! { + __BindgenBitfieldUnit<[u8; #size], #align> + }); + + tokens +} + pub mod ast_ty { use ir::context::BindgenContext; use ir::function::FunctionSig; @@ -143,13 +178,6 @@ pub mod ast_ty { tokens } - /// Returns hex representation of the given value. - pub fn hex_expr(val: u64) -> quote::Tokens { - let mut tokens = quote! {}; - tokens.append(format!("{:#x}", val)); - tokens - } - pub fn byte_array_expr(bytes: &[u8]) -> quote::Tokens { let mut bytes: Vec<_> = bytes.iter().cloned().collect(); bytes.push(0); |