diff options
author | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-05-04 17:55:47 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <me@emiliocobos.me> | 2016-05-04 17:55:47 +0200 |
commit | 0ea208b7e6ef54fa1f40efb7912d7040cf2e4fa9 (patch) | |
tree | e6d5ac219178ad3330bb2e12543fbe080a7db22f | |
parent | eb64428b3efd78fcded7a299534da08785f3b7b4 (diff) |
Wrap C++ `mutable` types in rust *Cells
-rw-r--r-- | src/clang.rs | 6 | ||||
-rw-r--r-- | src/clangll.rs | 1 | ||||
-rw-r--r-- | src/gen.rs | 22 | ||||
-rw-r--r-- | src/parser.rs | 9 | ||||
-rw-r--r-- | src/types.rs | 9 | ||||
-rw-r--r-- | tests/expectations/mutable.rs | 43 | ||||
-rw-r--r-- | tests/headers/mutable.hpp | 14 |
7 files changed, 97 insertions, 7 deletions
diff --git a/src/clang.rs b/src/clang.rs index ed2ec3cd..b7d6b5c7 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -205,6 +205,12 @@ impl Cursor { } } + pub fn is_mutable_field(&self) -> bool { + unsafe { + clang_CXXField_isMutable(self.x) != 0 + } + } + // CXX method pub fn method_is_static(&self) -> bool { unsafe { diff --git a/src/clangll.rs b/src/clangll.rs index 984f0aa5..dfd92cee 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -1235,6 +1235,7 @@ extern "C" { pub fn clang_CXXMethod_isPureVirtual(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isStatic(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isVirtual(C: CXCursor) -> c_uint; + pub fn clang_CXXField_isMutable(C: CXCursor) -> c_uint; pub fn clang_getTemplateCursorKind(C: CXCursor) -> Enum_CXCursorKind; pub fn clang_getSpecializedCursorTemplate(C: CXCursor) -> CXCursor; pub fn clang_getCursorReferenceNameRange(C: CXCursor, @@ -1049,7 +1049,25 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> } } - let f_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path)); + let rust_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path)); + + // Wrap mutable fields in a Cell/UnsafeCell + let rust_ty = if f.mutable { + if !f_ty.can_derive_copy() { + quote_ty!(&ctx.ext_cx, ::std::cell::UnsafeCell<$rust_ty>) + // We can only wrap in a cell for non-copiable types, since + // Cell<T>: Clone, but not Copy. + // + // It's fine though, since mutating copiable types is trivial + // and doesn't make a lot of sense marking fields as `mutable`. + } else if !ci.can_derive_copy() { + quote_ty!(&ctx.ext_cx, ::std::cell::Cell<$rust_ty>) + } else { + rust_ty + } + } else { + rust_ty + }; fields.push(respan(ctx.span, ast::StructField_ { kind: ast::NamedField( @@ -1057,7 +1075,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> ast::Visibility::Public, ), id: ast::DUMMY_NODE_ID, - ty: f_ty, + ty: rust_ty, attrs: mk_doc_attr(ctx, &f.comment) })); if bypass { diff --git a/src/parser.rs b/src/parser.rs index 32f46dff..774ebbbb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -558,6 +558,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, } let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs); + let mutable = cursor.is_mutable_field(); // NB: Overwritten in the case of non-integer bitfield let mut ty = conv_ty_resolving_typedefs(ctx, &cursor.cur_type(), cursor, is_class_typedef); @@ -661,13 +662,13 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, }; if should_replace { - *info = FieldInfo::new(name, ty, comment, bitfields); + *info = FieldInfo::new(name, ty, comment, bitfields, mutable); return CXChildVisit_Continue; } } } - let field = FieldInfo::new(name, ty, comment, bitfields); + let field = FieldInfo::new(name, ty, comment, bitfields, mutable); ci.members.push(CompMember::Field(field)); } CXCursor_StructDecl | @@ -700,7 +701,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, // Anonymous structs are legal in both C++ and C11 if ci2.borrow().was_unnamed { let ci2b = ci2.borrow(); - let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None); + let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None, false); ci.members.push(CompMember::Field(field)); } }); @@ -758,7 +759,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, ci.typedefs.extend(info.borrow().typedefs.clone().into_iter()); } - let field = FieldInfo::new(fieldname, ty, "".to_owned(), None); + let field = FieldInfo::new(fieldname, ty, "".to_owned(), None, false); if !found_virtual_base && cursor.is_virtual_base() { ci.members.insert(0, CompMember::Field(field)); ci.has_vtable = true; diff --git a/src/types.rs b/src/types.rs index cc335d41..c7b9e530 100644 --- a/src/types.rs +++ b/src/types.rs @@ -580,15 +580,22 @@ pub struct FieldInfo { pub ty: Type, pub comment: String, pub bitfields: Option<Vec<(String, u32)>>, + /// If the C++ field is marked as `mutable` + pub mutable: bool, } impl FieldInfo { - pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> 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, } } } diff --git a/tests/expectations/mutable.rs b/tests/expectations/mutable.rs new file mode 100644 index 00000000..62b4c524 --- /dev/null +++ b/tests/expectations/mutable.rs @@ -0,0 +1,43 @@ +/* automatically generated by rust-bindgen */ + + +#![feature(const_fn)] +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Struct_C { + pub m_member: ::std::os::raw::c_int, + pub m_other: ::std::os::raw::c_int, +} +impl ::std::clone::Clone for Struct_C { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_Struct_C() { + assert_eq!(::std::mem::size_of::<Struct_C>() , 8usize); + assert_eq!(::std::mem::align_of::<Struct_C>() , 4usize); +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_NonCopiable { + pub m_member: ::std::cell::Cell<::std::os::raw::c_int>, +} +#[test] +fn bindgen_test_layout_Struct_NonCopiable() { + assert_eq!(::std::mem::size_of::<Struct_NonCopiable>() , 4usize); + assert_eq!(::std::mem::align_of::<Struct_NonCopiable>() , 4usize); +} +#[repr(C)] +#[derive(Debug)] +pub struct Struct_NonCopiableWithNonCopiableMutableMember { + pub m_member: ::std::cell::UnsafeCell<Struct_NonCopiable>, +} +#[test] +fn bindgen_test_layout_Struct_NonCopiableWithNonCopiableMutableMember() { + assert_eq!(::std::mem::size_of::<Struct_NonCopiableWithNonCopiableMutableMember>() + , 4usize); + assert_eq!(::std::mem::align_of::<Struct_NonCopiableWithNonCopiableMutableMember>() + , 4usize); +} diff --git a/tests/headers/mutable.hpp b/tests/headers/mutable.hpp new file mode 100644 index 00000000..b61a1031 --- /dev/null +++ b/tests/headers/mutable.hpp @@ -0,0 +1,14 @@ +class C { + mutable int m_member; + int m_other; +}; + +class NonCopiable { + mutable int m_member; + + ~NonCopiable() {}; +}; + +class NonCopiableWithNonCopiableMutableMember { + mutable NonCopiable m_member; +}; |