diff options
author | Sergey Pepyakin <s.pepyakin@gmail.com> | 2017-10-04 16:36:54 +0300 |
---|---|---|
committer | Sergey Pepyakin <s.pepyakin@gmail.com> | 2017-10-05 11:55:57 +0300 |
commit | c4c4ae27483970092476ae50738e3f7040672bf2 (patch) | |
tree | 1c149ea4c1969834c8ad5c417506b59f0676580f | |
parent | 8387c7f5888e4e9b17828cfc6803dbbbd4fb6e47 (diff) |
Eagerly generate bitfield accessor names
Also clean a bit.
-rw-r--r-- | src/codegen/mod.rs | 60 | ||||
-rw-r--r-- | src/ir/comp.rs | 145 | ||||
-rw-r--r-- | src/ir/context.rs | 46 |
3 files changed, 176 insertions, 75 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 5e4bb5fe..ea9fec41 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1202,7 +1202,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { (&unit_field_name, unit_field_int_ty.clone()), ); - let param_name = bitfield_getter_name(ctx, parent, bf.name().unwrap()); + let param_name = bitfield_getter_name(ctx, bf); let bitfield_ty_item = ctx.resolve_item(bf.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); let bitfield_ty = @@ -1236,59 +1236,21 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { } } -fn parent_has_method( - ctx: &BindgenContext, - parent: &CompInfo, - name: &str, -) -> bool { - parent.methods().iter().any(|method| { - let method_name = match *ctx.resolve_item(method.signature()).kind() { - ItemKind::Function(ref func) => func.name(), - ref otherwise => { - panic!( - "a method's signature should always be a \ - item of kind ItemKind::Function, found: \ - {:?}", - otherwise - ) - } - }; - - method_name == name || ctx.rust_mangle(&method_name) == name - }) -} - fn bitfield_getter_name( ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str, + bitfield: &Bitfield, ) -> quote::Tokens { - let name = ctx.rust_mangle(bitfield_name); - - if parent_has_method(ctx, parent, &name) { - let mut name = name.to_string(); - name.push_str("_bindgen_bitfield"); - let name = ctx.rust_ident(name); - return quote! { #name }; - } - - let name = ctx.rust_ident(name); + let name = bitfield.getter_name(); + let name = ctx.rust_ident_raw(name); quote! { #name } } fn bitfield_setter_name( ctx: &BindgenContext, - parent: &CompInfo, - bitfield_name: &str, + bitfield: &Bitfield, ) -> quote::Tokens { - let setter = format!("set_{}", bitfield_name); - let mut setter = ctx.rust_mangle(&setter).to_string(); - - if parent_has_method(ctx, parent, &setter) { - setter.push_str("_bindgen_bitfield"); - } - - let setter = ctx.rust_ident(setter); + let setter = bitfield.setter_name(); + let setter = ctx.rust_ident_raw(setter); quote! { #setter } } @@ -1301,7 +1263,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { _fields_should_be_private: bool, _codegen_depth: usize, _accessor_kind: FieldAccessorKind, - parent: &CompInfo, + _parent: &CompInfo, _result: &mut CodegenResult, _struct_layout: &mut StructLayoutTracker, _fields: &mut F, @@ -1311,11 +1273,9 @@ impl<'a> FieldCodegen<'a> for Bitfield { F: Extend<quote::Tokens>, M: Extend<quote::Tokens>, { - // Should never be called with name() as None, as codegen can't be done - // on an anonymous bitfield let prefix = ctx.trait_prefix(); - let getter_name = bitfield_getter_name(ctx, parent, self.name().unwrap()); - let setter_name = bitfield_setter_name(ctx, parent, self.name().unwrap()); + let getter_name = bitfield_getter_name(ctx, self); + let setter_name = bitfield_setter_name(ctx, self); let unit_field_ident = quote::Ident::new(unit_field_name); let bitfield_ty_item = ctx.resolve_item(self.ty()); diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 80c2bde1..91f29a51 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -292,6 +292,16 @@ pub struct Bitfield { /// The field data for this bitfield. data: FieldData, + + /// Name of the generated Rust getter for this bitfield. + /// + /// Should be assigned before codegen. + getter_name: Option<String>, + + /// Name of the generated Rust setter for this bitfield. + /// + /// Should be assigned before codegen. + setter_name: Option<String>, } impl Bitfield { @@ -302,6 +312,8 @@ impl Bitfield { Bitfield { offset_into_unit: offset_into_unit, data: raw.0, + getter_name: None, + setter_name: None, } } @@ -331,6 +343,35 @@ impl Bitfield { pub fn width(&self) -> u32 { self.data.bitfield().unwrap() } + + /// Get the name of this bitfield. + fn name(&self) -> Option<&str> { + self.data.name() + } + + /// Name of the generated Rust getter for this bitfield. + /// + /// Panics if called before assigning bitfield accessor names or if + /// this bitfield have no name. + pub fn getter_name(&self) -> &str { + assert!(self.name().is_some(), "`Bitfield::getter_name` called on anonymous field"); + self.getter_name.as_ref().expect( + "`Bitfield::getter_name` should only be called after\ + assigning bitfield accessor names", + ) + } + + /// Name of the generated Rust setter for this bitfield. + /// + /// Panics if called before assigning bitfield accessor names or if + /// this bitfield have no name. + pub fn setter_name(&self) -> &str { + assert!(self.name().is_some(), "`Bitfield::setter_name` called on anonymous field"); + self.setter_name.as_ref().expect( + "`Bitfield::setter_name` should only be called\ + after assigning bitfield accessor names", + ) + } } impl FieldMethods for Bitfield { @@ -661,30 +702,102 @@ impl CompFields { ); } - fn deanonymize_fields(&mut self) { + fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) { + use std::collections::HashMap; + let fields = match *self { - CompFields::AfterComputingBitfieldUnits(ref mut fields) => { - fields - } + CompFields::AfterComputingBitfieldUnits(ref mut fields) => fields, CompFields::BeforeComputingBitfieldUnits(_) => { panic!("Not yet computed bitfield units."); } }; + fn has_method( + methods: &[Method], + ctx: &BindgenContext, + name: &str, + ) -> bool { + methods.iter().any(|method| { + let method_name = ctx.resolve_func(method.signature()).name(); + method_name == name || ctx.rust_mangle(&method_name) == name + }) + } + + struct AccessorNamesPair { + getter: String, + setter: String, + } + + let mut accessor_names: HashMap<String, AccessorNamesPair> = fields + .iter() + .flat_map(|field| match *field { + Field::Bitfields(ref bu) => &*bu.bitfields, + Field::DataMember(_) => &[], + }) + .filter_map(|bitfield| bitfield.name()) + .map(|bitfield_name| { + let bitfield_name = bitfield_name.to_string(); + let getter = { + let mut getter = + ctx.rust_mangle(&bitfield_name).to_string(); + if has_method(methods, ctx, &getter) { + getter.push_str("_bindgen_bitfield"); + } + getter + }; + let setter = { + let setter = format!("set_{}", bitfield_name); + let mut setter = ctx.rust_mangle(&setter).to_string(); + if has_method(methods, ctx, &setter) { + setter.push_str("_bindgen_bitfield"); + } + setter + }; + ( + bitfield_name, + AccessorNamesPair { + getter, + setter, + }, + ) + }) + .collect(); + let mut anon_field_counter = 0; for field in fields.iter_mut() { - let field_data = match *field { - Field::DataMember(ref mut fd) => fd, - Field::Bitfields(_) => continue, - }; + match *field { + Field::DataMember(FieldData { + ref mut name, .. + }) => { + if let Some(_) = *name { + continue; + } - if let Some(_) = field_data.name { - continue; - } + anon_field_counter += 1; + let generated_name = + format!("__bindgen_anon_{}", anon_field_counter); + *name = Some(generated_name); + } + Field::Bitfields(ref mut bu) => for bitfield in + &mut bu.bitfields + { + if bitfield.name().is_none() { + continue; + } + + let (getter, setter) = + match accessor_names.remove(bitfield.name().unwrap()) { + Some(AccessorNamesPair { + getter, + setter, + }) => (getter, setter), + None => continue, + }; - anon_field_counter += 1; - let name = format!("__bindgen_anon_{}", anon_field_counter); - field_data.name = Some(name); + bitfield.getter_name = Some(getter); + bitfield.setter_name = Some(setter); + }, + } } } } @@ -1397,8 +1510,8 @@ impl CompInfo { } /// Assign for each anonymous field a generated name. - pub fn deanonymize_fields(&mut self) { - self.fields.deanonymize_fields(); + pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) { + self.fields.deanonymize_fields(ctx, &self.methods); } /// Returns whether the current union can be represented as a Rust `union` diff --git a/src/ir/context.rs b/src/ir/context.rs index e9a9b504..706531ef 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -15,6 +15,7 @@ use super::module::{Module, ModuleKind}; use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; +use super::function::Function; use super::super::time::Timer; use BindgenOptions; use callbacks::ParseCallbacks; @@ -994,12 +995,31 @@ impl BindgenContext { /// Assign a new generated name for each anonymous field. fn deanonymize_fields(&mut self) { let _t = self.timer("deanonymize_fields"); - let comp_types = self.items - .values_mut() - .filter_map(|item| item.kind_mut().as_type_mut()) - .filter_map(Type::as_comp_mut); - for comp_info in comp_types { - comp_info.deanonymize_fields(); + + let comp_item_ids: Vec<ItemId> = self.items + .iter() + .filter_map(|(id, item)| { + if let Some(ty) = item.kind().as_type() { + if let Some(_comp) = ty.as_comp() { + return Some(id); + } + } + None + }) + .cloned() + .collect(); + + for id in comp_item_ids { + let mut item = self.items.remove(&id).unwrap(); + + item.kind_mut() + .as_type_mut() + .unwrap() + .as_comp_mut() + .unwrap() + .deanonymize_fields(self); + + self.items.insert(id, item); } } @@ -1391,12 +1411,20 @@ impl BindgenContext { self.root_module } - /// Resolve the given `ItemId` as a type. + /// Resolve a type with the given id. /// - /// Panics if there is no item for the given `ItemId` or if the resolved + /// Panics if there is no item for the given `TypeId` or if the resolved /// item is not a `Type`. pub fn resolve_type(&self, type_id: TypeId) -> &Type { - self.items.get(&type_id.into()).unwrap().kind().expect_type() + self.resolve_item(type_id).kind().expect_type() + } + + /// Resolve a function with the given id. + /// + /// Panics if there is no item for the given `FunctionId` or if the resolved + /// item is not a `Function`. + pub fn resolve_func(&self, func_id: FunctionId) -> &Function { + self.resolve_item(func_id).kind().expect_function() } /// Resolve the given `ItemId` as a type, or `None` if there is no item with |