diff options
author | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-08-20 22:32:16 -0700 |
---|---|---|
committer | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-09-16 11:34:07 -0700 |
commit | cfdf15f5d04d4fbca3e7fcb46a1dd658ade973cd (patch) | |
tree | f7d2087332f4506bb836dce901bc181e5ffc7fba /src/types.rs | |
parent | bbd6b2c9919e02642a8874e5ceb2ba3b5c76adec (diff) |
Rewrite the core of the binding generator.
TL;DR: The binding generator is a mess as of right now. At first it was funny
(in a "this is challenging" sense) to improve on it, but this is not
sustainable.
The truth is that the current architecture of the binding generator is a huge
pile of hacks, so these few days I've been working on rewriting it with a few
goals.
1) Have the hacks as contained and identified as possible. They're sometimes
needed because how clang exposes the AST, but ideally those hacks are well
identified and don't interact randomly with each others.
As an example, in the current bindgen when scanning the parameters of a
function that references a struct clones all the struct information, then if
the struct name changes (because we mangle it), everything breaks.
2) Support extending the bindgen output without having to deal with clang. The
way I'm aiming to do this is separating completely the parsing stage from
the code generation one, and providing a single id for each item the binding
generator provides.
3) No more random mutation of the internal representation from anywhere. That
means no more Rc<RefCell<T>>, no more random circular references, no more
borrow_state... nothing.
4) No more deduplication of declarations before code generation.
Current bindgen has a stage, called `tag_dup_decl`[1], that takes care of
deduplicating declarations. That's completely buggy, and for C++ it's a
complete mess, since we YOLO modify the world.
I've managed to take rid of this using the clang canonical declaration, and
the definition, to avoid scanning any type/item twice.
5) Code generation should not modify any internal data structure. It can lookup
things, traverse whatever it needs, but not modifying randomly.
6) Each item should have a canonical name, and a single source of mangling
logic, and that should be computed from the inmutable state, at code
generation.
I've put a few canonical_name stuff in the code generation phase, but it's
still not complete, and should change if I implement namespaces.
Improvements pending until this can land:
1) Add support for missing core stuff, mainly generating functions (note that
we parse the signatures for types correctly though), bitfields, generating
C++ methods.
2) Add support for the necessary features that were added to work around some
C++ pitfalls, like opaque types, etc...
3) Add support for the sugar that Manish added recently.
4) Optionally (and I guess this can land without it, because basically nobody
uses it since it's so buggy), bring back namespace support.
These are not completely trivial, but I think I can do them quite easily with
the current architecture.
I'm putting the current state of affairs here as a request for comments... Any
thoughts? Note that there are still a few smells I want to eventually
re-redesign, like the ParseError::Recurse thing, but until that happens I'm
way happier with this kind of architecture.
I'm keeping the old `parser.rs` and `gen.rs` in tree just for reference while I
code, but they will go away.
[1]: https://github.com/Yamakaky/rust-bindgen/blob/master/src/gen.rs#L448
Diffstat (limited to 'src/types.rs')
-rw-r--r-- | src/types.rs | 882 |
1 files changed, 0 insertions, 882 deletions
diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 60af3f59..00000000 --- a/src/types.rs +++ /dev/null @@ -1,882 +0,0 @@ -use std::cell::Cell; -use hacks::refcell::RefCell; -use std::fmt; -use std::rc::Rc; -use std::collections::HashMap; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -use syntax::abi; - -pub use self::Global::*; -pub use self::Type::*; -pub use self::IKind::*; -pub use self::FKind::*; -use clang::{self, Cursor}; - -use parser::{Annotations, Accessor}; - -static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT; - -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct ModuleId(usize); -pub static ROOT_MODULE_ID: ModuleId = ModuleId(0); - -impl ModuleId { - pub fn next() -> ModuleId { - ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1) - } -} - -pub type ModuleMap = HashMap<ModuleId, Module>; - -#[derive(Clone)] -pub struct Module { - pub name: String, - pub globals: Vec<Global>, - pub parent_id: Option<ModuleId>, - // Just for convenience - pub children_ids: Vec<ModuleId>, - /// Types that must be substituted in this module, - /// in the form original_name -> substituted_type - pub translations: HashMap<String, Global>, -} - -impl Module { - pub fn new(name: String, parent_id: Option<ModuleId>) -> Self { - Module { - name: name, - globals: vec![], - parent_id: parent_id, - children_ids: vec![], - translations: HashMap::new(), - } - } - - #[allow(dead_code)] - pub fn add_global(&mut self, g: Global) { - self.globals.push(g) - } -} - -#[derive(Clone, PartialEq)] -pub enum Global { - GType(Rc<RefCell<TypeInfo>>), - GComp(Rc<RefCell<CompInfo>>), - GCompDecl(Rc<RefCell<CompInfo>>), - GEnum(Rc<RefCell<EnumInfo>>), - GEnumDecl(Rc<RefCell<EnumInfo>>), - GVar(Rc<RefCell<VarInfo>>), - GFunc(Rc<RefCell<VarInfo>>), - GOther -} - -impl Global { - // XXX prevent this dumb to_owned()... didn't want to deal with the borrowed lifetime - pub fn name(&self) -> String { - match *self { - GType(ref info) => info.borrow().name.to_owned(), - GComp(ref info) - | GCompDecl(ref info) => info.borrow().name.to_owned(), - GEnum(ref info) - | GEnumDecl(ref info) => info.borrow().name.to_owned(), - GVar(ref info) - | GFunc(ref info) => info.borrow().name.to_owned(), - GOther => "".to_owned(), - } - } - - pub fn layout(&self) -> Option<Layout> { - Some(match *self { - GType(ref info) => info.borrow().layout, - GComp(ref info) - | GCompDecl(ref info) => info.borrow().layout, - GEnum(ref info) - | GEnumDecl(ref info) => info.borrow().layout, - GVar(_) - | GFunc(_) - | GOther => return None, - }) - } - - pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> { - match *self { - GComp(ref i) - | GCompDecl(ref i) => i.clone(), - _ => panic!("global_compinfo") - } - } - - pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> { - match *self { - GEnum(ref i) - | GEnumDecl(ref i) => i.clone(), - _ => panic!("global_enuminfo") - } - } - - pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> { - match *self { - GType(ref i) => i.clone(), - _ => panic!("global_typeinfo") - } - } - - pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> { - match *self { - GVar(ref i) - | GFunc(ref i) => i.clone(), - _ => panic!("global_varinfo") - } - } - - pub fn to_type(self) -> Type { - match self { - GType(ti) => TNamed(ti), - GComp(ci) - | GCompDecl(ci) => TComp(ci), - GEnum(ei) - | GEnumDecl(ei) => TEnum(ei), - GVar(_) - | GFunc(_) - | GOther => TVoid, - } - } -} - -impl fmt::Debug for Global { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - GType(ref ti) => ti.borrow().fmt(f), - GComp(ref ci) - | GCompDecl(ref ci) => ci.borrow().fmt(f), - GEnum(ref ei) - | GEnumDecl(ref ei) => ei.borrow().fmt(f), - GVar(ref vi) - | GFunc(ref vi) => vi.borrow().fmt(f), - GOther => "*".fmt(f), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct FuncSig { - pub ret_ty: Box<Type>, - pub args: Vec<(String, Type)>, - pub is_variadic: bool, - pub is_safe: bool, - pub abi: abi::Abi, -} - -// NOTE: Remember to add your new variant to the PartialEq implementation below! -#[derive(Clone, Debug)] -pub enum Type { - TVoid, - TInt(IKind, Layout), - TFloat(FKind, Layout), - TPtr(Box<Type>, bool, bool, Layout), - TArray(Box<Type>, usize, Layout), - TFuncProto(FuncSig), - TFuncPtr(FuncSig), - TNamed(Rc<RefCell<TypeInfo>>), - TComp(Rc<RefCell<CompInfo>>), - TEnum(Rc<RefCell<EnumInfo>>) -} - -/// Compares to Rc<T> types looking first at the value they point to. -/// -/// This is needed to avoid infinite recursion in things like virtual function -/// signatures. -fn ref_ptr_aware_eq<T: PartialEq>(one: &Rc<T>, other: &Rc<T>) -> bool { - &**one as *const T == &**other as *const T || - **one == **other -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (&TVoid, &TVoid) - => true, - (&TInt(ref kind, ref l), &TInt(ref o_kind, ref o_l)) - => kind == o_kind && l == o_l, - (&TFloat(ref kind, ref l), &TFloat(ref o_kind, ref o_l)) - => kind == o_kind && l == o_l, - (&TPtr(ref ty, is_const, is_ref, ref l), &TPtr(ref o_ty, o_is_const, o_is_ref, ref o_l)) - => is_const == o_is_const && is_ref == o_is_ref && l == o_l && ty == o_ty, - (&TArray(ref ty, count, ref l), &TArray(ref o_ty, o_count, ref o_l)) - => count == o_count && l == o_l && ty == o_ty, - (&TFuncProto(ref sig), &TFuncProto(ref o_sig)) - => sig == o_sig, - (&TNamed(ref ti), &TNamed(ref o_ti)) - => ref_ptr_aware_eq(ti, o_ti), - (&TComp(ref ci), &TComp(ref o_ci)) - => ref_ptr_aware_eq(ci, o_ci), - (&TEnum(ref ei), &TEnum(ref o_ei)) - => ref_ptr_aware_eq(ei, o_ei), - _ => false, - } - } -} - -impl Type { - #[allow(dead_code)] - pub fn name(&self) -> Option<String> { - match *self { - TNamed(ref info) => Some(info.borrow().name.clone()), - TComp(ref info) => Some(info.borrow().name.clone()), - TEnum(ref info) => Some(info.borrow().name.clone()), - TArray(ref t, _, _) => t.name(), - TPtr(ref t, _, _, _) => t.name(), - _ => None - } - } - - pub fn signature_contains_type(&self, other: &Type) -> bool { - self == other || match *self { - TPtr(ref t, _, _, _) => t.signature_contains_type(other), - TArray(ref t, _, _) => t.signature_contains_type(other), - TComp(ref info) => info.borrow().signature_contains_type(other), - _ => false, - } - } - - // XXX Add this info to enums? - pub fn was_unnamed(&self) -> bool { - match *self { - TComp(ref ci) => ci.borrow().was_unnamed, - TArray(ref t, _, _) => t.was_unnamed(), - TPtr(ref t, _, _, _) => t.was_unnamed(), - _ => false, - } - } - - pub fn get_outermost_composite(&self) -> Option<Rc<RefCell<CompInfo>>> { - match *self { - TComp(ref ci) => Some(ci.clone()), - TArray(ref t, _, _) => t.get_outermost_composite(), - TPtr(ref t, _, _, _) => t.get_outermost_composite(), - _ => None, - } - } - - pub fn size(&self) -> usize { - self.layout().map(|l| l.size).unwrap_or(0) - } - - pub fn align(&self) -> usize { - self.layout().map(|l| l.align).unwrap_or(0) - } - - pub fn layout(&self) -> Option<Layout> { - Some(match *self { - TInt(_, l) => l.clone(), - TFloat(_, l) => l.clone(), - TPtr(_, _, _, l) => l.clone(), - TArray(_, _, l) => l.clone(), - TComp(ref ci) => ci.borrow().layout.clone(), - TEnum(ref ei) => ei.borrow().layout.clone(), - // Test first with the underlying type layout, else with the reported one - // This fixes a weird bug in SM when it can't find layout for uint32_t - TNamed(ref ti) => ti.borrow().ty.layout().unwrap_or(ti.borrow().layout.clone()), - TVoid | - TFuncProto(..) | - TFuncPtr(..) => return None, - }) - } - - pub fn can_derive_debug(&self) -> bool { - !self.is_opaque() && match *self { - TArray(ref t, size, _) => size <= 32 && t.can_derive_debug(), - TNamed(ref ti) => ti.borrow().ty.can_derive_debug(), - TComp(ref comp) => comp.borrow().can_derive_debug(), - _ => true, - } - } - - // For some reason, deriving copies of an array of a type that is not known to be copy - // is a compile error. e.g.: - // - // #[derive(Copy)] - // struct A<T> { - // member: T, - // } - // - // is fine, while: - // - // #[derive(Copy)] - // struct A<T> { - // member: [T; 1], - // } - // - // is an error. - // - // That's the point of the existance of can_derive_copy_in_array(). - pub fn can_derive_copy_in_array(&self) -> bool { - match *self { - TVoid => false, - TNamed(ref ti) => ti.borrow().ty.can_derive_copy_in_array(), - TArray(ref t, _, _) => t.can_derive_copy_in_array(), - ref t => t.can_derive_copy(), - } - } - - pub fn can_derive_copy(&self) -> bool { - !self.is_opaque() && match *self { - TArray(ref t, _, _) => t.can_derive_copy_in_array(), - TNamed(ref ti) => ti.borrow().ty.can_derive_copy(), - TComp(ref comp) => comp.borrow().can_derive_copy(), - _ => true, - } - } - - pub fn is_opaque(&self) -> bool { - match *self { - TArray(ref t, _, _) => t.is_opaque(), - TPtr(ref t, _, _, _) => t.is_opaque(), - TNamed(ref ti) => ti.borrow().opaque || ti.borrow().ty.is_opaque(), - TComp(ref ci) => ci.borrow().is_opaque(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn is_union_like(&self) -> bool { - match *self { - TArray(ref t, _, _) => t.is_union_like(), - TPtr(ref t, _, _, _) => t.is_union_like(), - TNamed(ref ti) => ti.borrow().ty.is_union_like(), - TComp(ref ci) => ci.borrow().kind == CompKind::Union, - _ => false, - } - } - - // If a type is opaque we conservatively - // assume it has destructor - pub fn has_destructor(&self) -> bool { - self.is_opaque() || match *self { - TArray(ref t, _, _) => t.has_destructor(), - TNamed(ref ti) => ti.borrow().ty.has_destructor(), - TComp(ref ci) => ci.borrow().has_destructor(), - _ => false, - } - } - - pub fn is_translatable(&self) -> bool { - match *self { - TVoid => false, - TArray(ref t, _, _) => t.is_translatable(), - TComp(ref ci) => ci.borrow().is_translatable(), - // NB: TNamed explicitely ommited here - _ => true, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Layout { - pub size: usize, - pub align: usize, - pub packed: bool, -} - -impl Layout { - pub fn new(size: usize, align: usize) -> Self { - Layout { size: size, align: align, packed: false } - } - - // TODO: make this fallible using fallible_size(). - pub fn from_ty(ty: &clang::Type) -> Self { - Self::new(ty.size(), ty.align()) - } - - pub fn zero() -> Layout { - Layout { size: 0, align: 0, packed: false } - } - - pub fn is_zero(&self) -> bool { - *self == Self::zero() - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum IKind { - IBool, - ISChar, - IUChar, - IShort, - IUShort, - IInt, - IUInt, - ILong, - IULong, - ILongLong, - IULongLong -} - -impl IKind { - #[allow(dead_code)] - pub fn is_signed(self) -> bool { - match self { - IBool => false, - ISChar => true, - IUChar => false, - IShort => true, - IUShort => false, - IInt => true, - IUInt => false, - ILong => true, - IULong => false, - ILongLong => true, - IULongLong => false, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum FKind { - FFloat, - FDouble -} - -#[derive(Clone, PartialEq, Debug)] -pub enum CompMember { - Field(FieldInfo), - Comp(Rc<RefCell<CompInfo>>), - Enum(Rc<RefCell<EnumInfo>>), -} - -#[derive(Copy, Clone, PartialEq)] -pub enum CompKind { - Struct, - Union, -} - -#[derive(Clone, PartialEq)] -pub struct CompInfo { - pub kind: CompKind, - pub name: String, - pub module_id: ModuleId, - pub filename: String, - pub comment: String, - pub members: Vec<CompMember>, - pub args: Vec<Type>, - pub methods: Vec<VarInfo>, - pub vmethods: Vec<VarInfo>, - pub ref_template: Option<Type>, - pub has_vtable: bool, - pub has_destructor: bool, - pub has_nonempty_base: bool, - pub hide: bool, - pub parser_cursor: Option<Cursor>, - /// If this struct should be replaced by an opaque blob. - /// - /// This is useful if for some reason we can't generate - /// the correct layout. - pub opaque: bool, - pub base_members: usize, - layout: Layout, - /// If this struct is explicitely marked as non-copiable. - pub no_copy: bool, - /// Typedef'd types names, that we'll resolve early to avoid name conflicts - pub typedefs: Vec<String>, - /// If this type has a template parameter which is not a type (e.g.: a size_t) - pub has_non_type_template_params: bool, - /// If this type was unnamed when parsed - pub was_unnamed: bool, - /// Set of static vars declared inside this class. - pub vars: Vec<Global>, - /// Used to detect if we've run in a can_derive_debug cycle while cycling - /// around the template arguments. - detect_derive_debug_cycle: Cell<bool>, - /// Used to detect if we've run in a has_destructor cycle while cycling - /// around the template arguments. - detect_has_destructor_cycle: Cell<bool>, - - /// Annotations on the decl - pub anno: Annotations, -} - -static mut UNNAMED_COUNTER: u32 = 0; - -fn unnamed_name(name: String, filename: &String) -> String { - if name.is_empty() { - let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER }; - format!("{}_unnamed_{}", filename, n) - } else { - name - } -} - -impl CompInfo { - pub fn new(name: String, - module_id: ModuleId, - filename: String, - comment: String, - kind: CompKind, - members: Vec<CompMember>, - layout: Layout, - anno: Annotations) -> CompInfo { - let was_unnamed = name.is_empty(); - CompInfo { - kind: kind, - module_id: module_id, - name: unnamed_name(name, &filename), - filename: filename, - comment: comment, - members: members, - args: vec![], - methods: vec![], - vmethods: vec![], - ref_template: None, - has_vtable: false, - has_destructor: false, - has_nonempty_base: false, - hide: false, - parser_cursor: None, - opaque: false, - no_copy: false, - base_members: 0, - layout: layout, - typedefs: vec![], - vars: vec![], - has_non_type_template_params: false, - was_unnamed: was_unnamed, - detect_derive_debug_cycle: Cell::new(false), - detect_has_destructor_cycle: Cell::new(false), - anno: anno, - } - } - - // Gets or computes the layout as appropriately. - pub fn layout(&self) -> Layout { - use std::cmp; - // The returned layout from clang is zero as of right now, but we should - // change it to be fallible to distinguish correctly between zero-sized - // types and unknown layout. - if !self.layout.is_zero() { - return self.layout.clone(); - } - - if self.args.is_empty() { - return self.layout.clone(); - } - - if self.kind == CompKind::Struct { - return self.layout.clone(); - } - - // If we're a union without known layout, we try to compute it from our - // members. This is not ideal, but clang fails to report the size for - // these kind of unions, see test/headers/template_union.hpp - let mut max_size = 0; - let mut max_align = 0; - for member in &self.members { - let layout = match *member { - CompMember::Field(ref f) => f.ty.layout().unwrap_or(Layout::zero()), - CompMember::Comp(ref ci) => ci.borrow().layout(), - CompMember::Enum(ref ei) => ei.borrow().layout.clone(), - }; - - max_size = cmp::max(max_size, layout.size); - max_align = cmp::max(max_align, layout.align); - } - - Layout::new(max_size, max_align) - } - - pub fn set_packed(&mut self, packed: bool) { - self.layout.packed = packed - } - - // Return the module id or the class declaration module id. - pub fn module_id(&self) -> ModuleId { - self.ref_template.as_ref().and_then(|t| if let TComp(ref ci) = *t { - Some(ci.borrow().module_id) - } else { - None - }).unwrap_or(self.module_id) - } - - pub fn can_derive_debug(&self) -> bool { - if self.hide || self.is_opaque() { - return false; - } - - if self.detect_derive_debug_cycle.get() { - println!("Derive debug cycle detected: {}!", self.name); - return true; - } - - match self.kind { - CompKind::Union => { - let size_divisor = if self.layout.align == 0 { 1 } else { self.layout.align }; - if self.layout.size / size_divisor > 32 { - return false; - } - - true - } - CompKind::Struct => { - self.detect_derive_debug_cycle.set(true); - - let can_derive_debug = self.args.iter().all(|ty| ty.can_derive_debug()) && - self.members.iter() - .all(|member| match *member { - CompMember::Field(ref f) => f.ty.can_derive_debug(), - _ => true, - }); - self.detect_derive_debug_cycle.set(false); - - can_derive_debug - } - } - } - - pub fn is_opaque(&self) -> bool { - if let Some(ref template) = self.ref_template { - if template.is_opaque() { - return true; - } - } - self.opaque - } - - pub fn has_destructor(&self) -> bool { - if self.detect_has_destructor_cycle.get() { - warn!("Cycle detected looking for destructors: {}!", self.name); - // Assume no destructor, since we don't have an explicit one. - return false; - } - - self.detect_has_destructor_cycle.set(true); - - let has_destructor = self.has_destructor || match self.kind { - CompKind::Union => false, - CompKind::Struct => { - // NB: We can't rely on a type with type parameters - // not having destructor. - // - // This is unfortunate, but... - self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) || - self.args.iter().any(|t| t.has_destructor()) || - self.members.iter().enumerate().any(|(index, m)| match *m { - CompMember::Field(ref f) => { - // Base members may not be resolved yet - if index < self.base_members { - f.ty.has_destructor() - } else { - f.ty.has_destructor() || !f.ty.is_translatable() - } - }, - _ => false, - }) - } - }; - - self.detect_has_destructor_cycle.set(false); - - has_destructor - } - - pub fn can_derive_copy(&self) -> bool { - if self.no_copy { - return false; - } - - // NOTE: Take into account that while unions in C and C++ are copied by - // default, the may have an explicit destructor in C++, so we can't - // defer this check just for the union case. - if self.has_destructor() { - return false; - } - - match self.kind { - CompKind::Union => true, - CompKind::Struct => { - // With template args, use a safe subset of the types, - // since copyability depends on the types itself. - self.ref_template.as_ref().map_or(true, |t| t.can_derive_copy()) && - self.members.iter().all(|m| match *m { - CompMember::Field(ref f) => f.ty.can_derive_copy(), - _ => true, - }) - } - } - } - - pub fn is_translatable(&self) -> bool { - match self.kind { - CompKind::Union => true, - CompKind::Struct => { - self.args.iter().all(|t| t != &TVoid) && !self.has_non_type_template_params - } - } - } - - pub fn signature_contains_type(&self, other: &Type) -> bool { - self.args.iter().any(|t| t.signature_contains_type(other)) - } -} - -impl fmt::Debug for CompInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CompInfo({}, ref: {:?}, args: {:?}, members: {:?}", self.name, self.ref_template, self.args, self.members) - } -} - -#[derive(Clone, PartialEq)] -pub struct FieldInfo { - pub name: String, - pub ty: Type, - pub comment: String, - pub bitfields: Option<Vec<(String, u32)>>, - /// If the C++ field is marked as `mutable` - pub mutable: bool, - /// True when field or enclosing struct - /// has a `<div rust-bindgen private>` annotation - pub private: bool, - /// Set by the `<div rust-bindgen accessor="..">` - /// annotation on a field or enclosing struct - pub accessor: Accessor, -} - -impl FieldInfo { - pub fn new(name: String, - ty: Type, - comment: String, - bitfields: Option<Vec<(String, u32)>>, - mutable: bool) -> FieldInfo { - FieldInfo { - name: name, - ty: ty, - comment: comment, - bitfields: bitfields, - mutable: mutable, - private: false, - accessor: Accessor::None, - } - } -} - -impl fmt::Debug for FieldInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct EnumInfo { - pub name: String, - pub module_id: ModuleId, - pub comment: String, - pub filename: String, - pub items: Vec<EnumItem>, - pub kind: IKind, - pub layout: Layout, -} - -impl EnumInfo { - pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo { - EnumInfo { - name: unnamed_name(name, &filename), - module_id: module_id, - comment: String::new(), - filename: filename, - items: items, - kind: kind, - layout: layout, - } - } -} - -impl fmt::Debug for EnumInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct EnumItem { - pub name: String, - pub comment: String, - pub val: i64 -} - -impl EnumItem { - pub fn new(name: String, comment: String, val: i64) -> EnumItem { - EnumItem { - name: name, - comment: comment, - val: val - } - } -} - -#[derive(Clone, PartialEq)] -pub struct TypeInfo { - pub name: String, - pub module_id: ModuleId, - pub comment: String, - pub ty: Type, - pub layout: Layout, - // TODO: Is this really useful? - // You can just make opaque the underlying type - pub opaque: bool, - pub hide: bool, -} - -impl TypeInfo { - pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo { - TypeInfo { - name: name, - module_id: module_id, - comment: String::new(), - ty: ty, - layout: layout, - opaque: false, - hide: false, - } - } -} - -impl fmt::Debug for TypeInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct VarInfo { - pub name: String, - pub mangled: String, - pub comment: String, - pub ty: Type, - //TODO: support non-integer constants - pub val: Option<i64>, - pub is_const: bool, - pub is_static: bool, -} - -impl VarInfo { - pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo { - let mangled = if name == mangled { - String::new() - } else { - mangled - }; - VarInfo { - name: name, - mangled: mangled, - comment: comment, - ty: ty, - val: None, - is_const: false, - is_static: false, - } - } -} - -impl fmt::Debug for VarInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} |