diff options
author | Nick Fitzgerald <fitzgen@gmail.com> | 2017-05-19 13:33:23 -0700 |
---|---|---|
committer | Nick Fitzgerald <fitzgen@gmail.com> | 2017-05-19 13:33:23 -0700 |
commit | a7f44bd38ba38053657f898aaa0f7c551715e43e (patch) | |
tree | 4efc92be3b717be7c1631f0313f0b6f884b67a27 /src/codegen/mod.rs | |
parent | cabfac71fc454196656ff63e5cc761294896831d (diff) |
Add bitfield allocation unit constructors
This commit gives bindgen the ability to generate constructors for bitfield
allocation units. This enables more ergonomic use of struct literals for
bindings structs that contain bitfields.
Additionally, when we are generating unstable Rust, these constructors are
marked as const functions. This enables the creation of const binding structs
that contain bitfields.
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 121 |
1 files changed, 120 insertions, 1 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index fdf61f40..28cddb5d 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1020,6 +1020,108 @@ impl<'a> FieldCodegen<'a> for FieldData { } } +impl BitfieldUnit { + /// Get the constructor name for this bitfield unit. + fn ctor_name(&self, ctx: &BindgenContext) -> ast::Ident { + let ctor_name = format!("new_bitfield_{}", self.nth()); + ctx.ext_cx().ident_of(&ctor_name) + } + + /// Get the initial bitfield unit constructor that just returns 0. This will + /// then be extended by each bitfield in the unit. See `extend_ctor_impl` + /// below. + fn initial_ctor_impl(&self, + ctx: &BindgenContext, + unit_field_int_ty: &P<ast::Ty>) + -> P<ast::Item> { + let ctor_name = self.ctor_name(ctx); + + // If we're generating unstable Rust, add the const. + let fn_prefix = if ctx.options().unstable_rust { + quote_tokens!(ctx.ext_cx(), pub const fn) + } else { + quote_tokens!(ctx.ext_cx(), pub fn) + }; + + quote_item!( + ctx.ext_cx(), + impl XxxUnused { + #[inline] + $fn_prefix $ctor_name() -> $unit_field_int_ty { + 0 + } + } + ).unwrap() + } +} + +impl Bitfield { + /// Extend an under construction bitfield unit constructor with this + /// bitfield. This involves two things: + /// + /// 1. Adding a parameter with this bitfield's name and its type. + /// + /// 2. Bitwise or'ing the parameter into the final value of the constructed + /// bitfield unit. + fn extend_ctor_impl(&self, + ctx: &BindgenContext, + parent: &CompInfo, + ctor_impl: P<ast::Item>, + ctor_name: &ast::Ident, + unit_field_int_ty: &P<ast::Ty>) + -> P<ast::Item> { + match ctor_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => { + assert_eq!(items.len(), 1); + + match items.get(0).unwrap().node { + ast::ImplItemKind::Method(ref sig, ref body) => { + let params = sig.decl.clone().unwrap().inputs; + let param_name = bitfield_getter_name(ctx, parent, self.name()); + + let bitfield_ty_item = ctx.resolve_item(self.ty()); + let bitfield_ty = bitfield_ty_item.expect_type(); + let bitfield_ty_layout = bitfield_ty.layout(ctx) + .expect("Bitfield without layout? Gah!"); + let bitfield_int_ty = BlobTyBuilder::new(bitfield_ty_layout).build(); + let bitfield_ty = bitfield_ty + .to_rust_ty_or_opaque(ctx, bitfield_ty_item); + + let offset = self.offset_into_unit(); + let mask = self.mask(); + + // If we're generating unstable Rust, add the const. + let fn_prefix = if ctx.options().unstable_rust { + quote_tokens!(ctx.ext_cx(), pub const fn) + } else { + quote_tokens!(ctx.ext_cx(), pub fn) + }; + + quote_item!( + ctx.ext_cx(), + impl XxxUnused { + #[inline] + $fn_prefix $ctor_name($params $param_name : $bitfield_ty) + -> $unit_field_int_ty { + let bitfield_unit_val = $body; + let $param_name = $param_name + as $bitfield_int_ty + as $unit_field_int_ty; + let mask = $mask as $unit_field_int_ty; + let $param_name = ($param_name << $offset) & mask; + bitfield_unit_val | $param_name + } + } + ).unwrap() + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} + impl<'a> FieldCodegen<'a> for BitfieldUnit { type Extra = (); @@ -1058,6 +1160,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { } }; + let ctor_name = self.ctor_name(ctx); + let mut ctor_impl = self.initial_ctor_impl(ctx, &unit_field_int_ty); + for bf in self.bitfields() { bf.codegen(ctx, fields_should_be_private, @@ -1069,8 +1174,22 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { fields, methods, (&unit_field_name, unit_field_int_ty.clone())); + + ctor_impl = bf.extend_ctor_impl(ctx, + parent, + ctor_impl, + &ctor_name, + &unit_field_int_ty); } + match ctor_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, items) => { + assert_eq!(items.len(), 1); + methods.extend(items.into_iter()); + }, + _ => unreachable!(), + }; + struct_layout.saw_bitfield_unit(self.layout()); } } @@ -1154,7 +1273,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); - let mask: usize = ((1usize << self.width()) - 1usize) << offset; + let mask: usize = self.mask(); let impl_item = quote_item!( ctx.ext_cx(), |