diff options
author | Manish Goregaokar <manishsmail@gmail.com> | 2016-07-20 20:23:27 +0530 |
---|---|---|
committer | Manish Goregaokar <manishsmail@gmail.com> | 2016-07-26 15:25:10 +0530 |
commit | 0fcf367becd11e1de017e832ff81262c1c5f6f6e (patch) | |
tree | ead7755046030e03da75cacbe50b07dfb9177343 | |
parent | 7ab0e2cda43339dbafec8026561b5207f40a9f16 (diff) |
Add support for 'unsafe fields'
-rw-r--r-- | src/gen.rs | 67 | ||||
-rw-r--r-- | src/parser.rs | 39 | ||||
-rw-r--r-- | src/types.rs | 17 | ||||
-rw-r--r-- | tests/expectations/accessors.rs | 194 | ||||
-rw-r--r-- | tests/expectations/private.rs | 52 | ||||
-rw-r--r-- | tests/headers/accessors.hpp | 46 | ||||
-rw-r--r-- | tests/headers/private.hpp | 21 |
7 files changed, 426 insertions, 10 deletions
@@ -19,6 +19,7 @@ use syntax::print::pprust::tts_to_string; use super::BindgenOptions; use super::LinkType; +use parser::Accessor; use types::*; use aster; @@ -840,6 +841,52 @@ fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, extra: &mut Vec<P<ast::It attrs } +fn gen_accessors(ctx: &mut GenCtx, name: &str, ty: &ast::Ty, accessor: Accessor, + methods: &mut Vec<ast::ImplItem>) { + if accessor == Accessor::None { + return; + } + let ident = ctx.ext_cx.ident_of(&format!("{}", name)); + let mutable_getter_name = ctx.ext_cx.ident_of(&format!("get_{}_mut", name)); + let getter_name = ctx.ext_cx.ident_of(&format!("get_{}", name)); + let imp = match accessor { + Accessor::Regular => quote_item!(&ctx.ext_cx, + impl X { + #[inline] + pub fn $getter_name(&self) -> & $ty { + & self.$ident + } + pub fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$ident + } + } + ), + Accessor::Unsafe => quote_item!(&ctx.ext_cx, + impl X { + #[inline] + pub unsafe fn $getter_name(&self) -> & $ty { + & self.$ident + } + pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$ident + } + } + ), + Accessor::Immutable => quote_item!(&ctx.ext_cx, + impl X { + #[inline] + pub fn $getter_name(&self) -> & $ty { + & self.$ident + } + } + ), + _ => return + }; + match imp.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => methods.extend(items.clone()), + _ => unreachable!() + } +} fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> { let layout = ci.layout; @@ -878,14 +925,15 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> }; if let Some(ref base) = base_vftable { - vffields.push(ast::StructField { + let field = ast::StructField { span: ctx.span, vis: ast::Visibility::Public, ident: Some(ctx.ext_cx.ident_of("_base")), id: ast::DUMMY_NODE_ID, ty: P(mk_ty(ctx, false, &[base.clone()])), attrs: vec![], - }); + }; + vffields.push(field); } for vm in ci.vmethods.iter() { @@ -1052,15 +1100,22 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> } else { rust_ty }; - - fields.push(ast::StructField { + let vis = if f.private { + ast::Visibility::Inherited + } else { + ast::Visibility::Public + }; + gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods); + let field = ast::StructField { span: ctx.span, ident: Some(ctx.ext_cx.ident_of(&f_name)), - vis: ast::Visibility::Public, + vis: vis, id: ast::DUMMY_NODE_ID, ty: rust_ty, attrs: mk_doc_attr(ctx, &f.comment) - }); + }; + fields.push(field); + if bypass { continue; } diff --git a/src/parser.rs b/src/parser.rs index de1242be..a09954c1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -122,6 +122,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { CXCursor_ClassTemplate | CXCursor_ClassDecl | CXCursor_StructDecl => { + let anno = Annotations::new(&cursor); let kind = if cursor.kind() == CXCursor_UnionDecl { CompKind::Union } else { @@ -159,7 +160,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { } }; - let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout); + let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout, anno); ci.parser_cursor = Some(cursor); // If it's an instantiation of another template, @@ -538,12 +539,34 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) { } } -struct Annotations { +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum Accessor { + None, + Regular, + Unsafe, + Immutable, +} + +#[derive(Clone, PartialEq, Debug)] +pub struct Annotations { opaque: bool, hide: bool, use_as: Option<String>, /// Disable deriving copy/clone on this struct. no_copy: bool, + // In the None case we fall back to the value specified + // in the enclosing decl + private: Option<bool>, + accessor: Option<Accessor>, +} + +fn parse_accessor(s: &str) -> Accessor { + match s { + "false" => Accessor::None, + "unsafe" => Accessor::Unsafe, + "immutable" => Accessor::Immutable, + _ => Accessor::Regular, + } } impl Annotations { @@ -553,6 +576,8 @@ impl Annotations { hide: false, use_as: None, no_copy: false, + private: None, + accessor: None }; anno.parse(&cursor.comment()); @@ -571,6 +596,10 @@ impl Annotations { "hide" => self.hide = true, "replaces" => self.use_as = Some(comment.get_tag_attr_value(i)), "nocopy" => self.no_copy = true, + "private" => self.private = Some(comment.get_tag_attr_value(i) != "false"), + "accessor" => { + self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i))) + }, _ => (), } } @@ -792,12 +821,16 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, if should_replace { *info = FieldInfo::new(name, ty, comment, bitfields, mutable); + info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); + info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); return CXChildVisit_Continue; } } } - let field = FieldInfo::new(name, ty, comment, bitfields, mutable); + let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable); + field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); + field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); ci.members.push(CompMember::Field(field)); } CXCursor_StructDecl | diff --git a/src/types.rs b/src/types.rs index 8036a75f..09ce4cb2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -13,6 +13,8 @@ pub use self::IKind::*; pub use self::FKind::*; use clang::Cursor; +use parser::{Annotations, Accessor}; + static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT; #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] @@ -446,6 +448,9 @@ pub struct CompInfo { /// 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; @@ -466,7 +471,8 @@ impl CompInfo { comment: String, kind: CompKind, members: Vec<CompMember>, - layout: Layout) -> CompInfo { + layout: Layout, + anno: Annotations) -> CompInfo { let was_unnamed = name.is_empty(); CompInfo { kind: kind, @@ -494,6 +500,7 @@ impl CompInfo { was_unnamed: was_unnamed, detect_derive_debug_cycle: Cell::new(false), detect_has_destructor_cycle: Cell::new(false), + anno: anno, } } @@ -640,6 +647,12 @@ pub struct FieldInfo { 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 { @@ -654,6 +667,8 @@ impl FieldInfo { comment: comment, bitfields: bitfields, mutable: mutable, + private: false, + accessor: Accessor::None, } } } diff --git a/tests/expectations/accessors.rs b/tests/expectations/accessors.rs new file mode 100644 index 00000000..8d314878 --- /dev/null +++ b/tests/expectations/accessors.rs @@ -0,0 +1,194 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_SomeAccessors { + pub mNoAccessor: ::std::os::raw::c_int, + /** <div rustbindgen accessor></div> */ + pub mBothAccessors: ::std::os::raw::c_int, + /** <div rustbindgen accessor="unsafe"></div> */ + pub mUnsafeAccessors: ::std::os::raw::c_int, + /** <div rustbindgen accessor="immutable"></div> */ + pub mImmutableAccessor: ::std::os::raw::c_int, +} +impl Struct_SomeAccessors { + #[inline] + pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mBothAccessors + } + pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { + &mut self.mBothAccessors + } + #[inline] + pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int { + &self.mUnsafeAccessors + } + pub unsafe fn get_mUnsafeAccessors_mut(&mut self) + -> &mut ::std::os::raw::c_int { + &mut self.mUnsafeAccessors + } + #[inline] + pub fn get_mImmutableAccessor(&self) -> &::std::os::raw::c_int { + &self.mImmutableAccessor + } +} +impl ::std::clone::Clone for Struct_SomeAccessors { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_SomeAccessors() { + assert_eq!(::std::mem::size_of::<Struct_SomeAccessors>() , 16usize); + assert_eq!(::std::mem::align_of::<Struct_SomeAccessors>() , 4usize); +} +/** <div rustbindgen accessor></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_AllAccessors { + pub mBothAccessors: ::std::os::raw::c_int, + pub mAlsoBothAccessors: ::std::os::raw::c_int, +} +impl Struct_AllAccessors { + #[inline] + pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mBothAccessors + } + pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { + &mut self.mBothAccessors + } + #[inline] + pub fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mAlsoBothAccessors + } + pub fn get_mAlsoBothAccessors_mut(&mut self) + -> &mut ::std::os::raw::c_int { + &mut self.mAlsoBothAccessors + } +} +impl ::std::clone::Clone for Struct_AllAccessors { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_AllAccessors() { + assert_eq!(::std::mem::size_of::<Struct_AllAccessors>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_AllAccessors>() , 4usize); +} +/** <div rustbindgen accessor="unsafe"></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_AllUnsafeAccessors { + pub mBothAccessors: ::std::os::raw::c_int, + pub mAlsoBothAccessors: ::std::os::raw::c_int, +} +impl Struct_AllUnsafeAccessors { + #[inline] + pub unsafe fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mBothAccessors + } + pub unsafe fn get_mBothAccessors_mut(&mut self) + -> &mut ::std::os::raw::c_int { + &mut self.mBothAccessors + } + #[inline] + pub unsafe fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mAlsoBothAccessors + } + pub unsafe fn get_mAlsoBothAccessors_mut(&mut self) + -> &mut ::std::os::raw::c_int { + &mut self.mAlsoBothAccessors + } +} +impl ::std::clone::Clone for Struct_AllUnsafeAccessors { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_AllUnsafeAccessors() { + assert_eq!(::std::mem::size_of::<Struct_AllUnsafeAccessors>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_AllUnsafeAccessors>() , 4usize); +} +/** <div rustbindgen accessor></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_ContradictAccessors { + pub mBothAccessors: ::std::os::raw::c_int, + /** <div rustbindgen accessor="false"></div> */ + pub mNoAccessors: ::std::os::raw::c_int, + /** <div rustbindgen accessor="unsafe"></div> */ + pub mUnsafeAccessors: ::std::os::raw::c_int, + /** <div rustbindgen accessor="immutable"></div> */ + pub mImmutableAccessor: ::std::os::raw::c_int, +} +impl Struct_ContradictAccessors { + #[inline] + pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { + &self.mBothAccessors + } + pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { + &mut self.mBothAccessors + } + #[inline] + pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int { + &self.mUnsafeAccessors + } + pub unsafe fn get_mUnsafeAccessors_mut(&mut self) + -> &mut ::std::os::raw::c_int { + &mut self.mUnsafeAccessors + } + #[inline] + pub fn get_mImmutableAccessor(&self) -> &::std::os::raw::c_int { + &self.mImmutableAccessor + } +} +impl ::std::clone::Clone for Struct_ContradictAccessors { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_ContradictAccessors() { + assert_eq!(::std::mem::size_of::<Struct_ContradictAccessors>() , 16usize); + assert_eq!(::std::mem::align_of::<Struct_ContradictAccessors>() , 4usize); +} +/** <div rustbindgen accessor replaces="Replaced"></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_Replaced { + pub mAccessor: ::std::os::raw::c_int, +} +impl Struct_Replaced { + #[inline] + pub fn get_mAccessor(&self) -> &::std::os::raw::c_int { &self.mAccessor } + pub fn get_mAccessor_mut(&mut self) -> &mut ::std::os::raw::c_int { + &mut self.mAccessor + } +} +impl ::std::clone::Clone for Struct_Replaced { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_Replaced() { + assert_eq!(::std::mem::size_of::<Struct_Replaced>() , 4usize); + assert_eq!(::std::mem::align_of::<Struct_Replaced>() , 4usize); +} +/** <div rustbindgen accessor></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_Wrapper { + pub mReplaced: Struct_Replaced, +} +impl Struct_Wrapper { + #[inline] + pub fn get_mReplaced(&self) -> &Struct_Replaced { &self.mReplaced } + pub fn get_mReplaced_mut(&mut self) -> &mut Struct_Replaced { + &mut self.mReplaced + } +} +impl ::std::clone::Clone for Struct_Wrapper { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_Wrapper() { + assert_eq!(::std::mem::size_of::<Struct_Wrapper>() , 4usize); + assert_eq!(::std::mem::align_of::<Struct_Wrapper>() , 4usize); +} diff --git a/tests/expectations/private.rs b/tests/expectations/private.rs new file mode 100644 index 00000000..7263e3ee --- /dev/null +++ b/tests/expectations/private.rs @@ -0,0 +1,52 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_HasPrivate { + pub mNotPrivate: ::std::os::raw::c_int, + /** <div rustbindgen private></div> */ + mIsPrivate: ::std::os::raw::c_int, +} +impl ::std::clone::Clone for Struct_HasPrivate { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_HasPrivate() { + assert_eq!(::std::mem::size_of::<Struct_HasPrivate>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_HasPrivate>() , 4usize); +} +/** <div rustbindgen private></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_VeryPrivate { + mIsPrivate: ::std::os::raw::c_int, + mIsAlsoPrivate: ::std::os::raw::c_int, +} +impl ::std::clone::Clone for Struct_VeryPrivate { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_VeryPrivate() { + assert_eq!(::std::mem::size_of::<Struct_VeryPrivate>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_VeryPrivate>() , 4usize); +} +/** <div rustbindgen private></div> */ +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_ContradictPrivate { + /** <div rustbindgen private=false></div> */ + mNotPrivate: ::std::os::raw::c_int, + mIsPrivate: ::std::os::raw::c_int, +} +impl ::std::clone::Clone for Struct_ContradictPrivate { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_ContradictPrivate() { + assert_eq!(::std::mem::size_of::<Struct_ContradictPrivate>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_ContradictPrivate>() , 4usize); +} diff --git a/tests/headers/accessors.hpp b/tests/headers/accessors.hpp new file mode 100644 index 00000000..4c23e35d --- /dev/null +++ b/tests/headers/accessors.hpp @@ -0,0 +1,46 @@ +struct SomeAccessors { + int mNoAccessor; + /** <div rustbindgen accessor></div> */ + int mBothAccessors; + /** <div rustbindgen accessor="unsafe"></div> */ + int mUnsafeAccessors; + /** <div rustbindgen accessor="immutable"></div> */ + int mImmutableAccessor; +}; + +/** <div rustbindgen accessor></div> */ +struct AllAccessors { + int mBothAccessors; + int mAlsoBothAccessors; +}; + +/** <div rustbindgen accessor="unsafe"></div> */ +struct AllUnsafeAccessors { + int mBothAccessors; + int mAlsoBothAccessors; +}; + +/** <div rustbindgen accessor></div> */ +struct ContradictAccessors { + int mBothAccessors; + /** <div rustbindgen accessor="false"></div> */ + int mNoAccessors; + /** <div rustbindgen accessor="unsafe"></div> */ + int mUnsafeAccessors; + /** <div rustbindgen accessor="immutable"></div> */ + int mImmutableAccessor; +}; + +/** <div rustbindgen accessor replaces="Replaced"></div> */ +struct Replacing { + int mAccessor; +}; + +struct Replaced { + int noOp; +}; + +/** <div rustbindgen accessor></div> */ +struct Wrapper { + Replaced mReplaced; +}; diff --git a/tests/headers/private.hpp b/tests/headers/private.hpp new file mode 100644 index 00000000..070bdddc --- /dev/null +++ b/tests/headers/private.hpp @@ -0,0 +1,21 @@ + +struct HasPrivate { + int mNotPrivate; + /** <div rustbindgen private></div> */ + int mIsPrivate; +}; + + +/** <div rustbindgen private></div> */ +struct VeryPrivate { + int mIsPrivate; + int mIsAlsoPrivate; +}; + + +/** <div rustbindgen private></div> */ +struct ContradictPrivate { + /** <div rustbindgen private=false></div> */ + int mNotPrivate; + int mIsPrivate; +}; |