summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPorter Smith <flowbish@gmail.com>2018-11-28 14:45:08 -0800
committerPorter Smith <flowbish@gmail.com>2018-11-28 15:07:27 -0800
commit94698e02a6c346ed20a2bf6d4217be9e308ddb15 (patch)
tree9f073ccdb84e0735758e1fdd47155e417cb0aaa7
parentadfc52a02c8d53878a6d9c19373cc4470e423aeb (diff)
Add source annotation to express explicit derives for a type.
This allows for explicit selection of which traits are derived for a type, e.g. deriving custom traits on particular types that need it. Example usage: ```C++ /// <div rustbindgen derive="Clone"></div> /// <div rustbindgen derive="MyDerivableTrait"></div> struct foo { ... }; ``` generates into ```Rust #[derive(Clone,MyDerivableTrait)] struct foo { ... } ```
-rw-r--r--src/codegen/mod.rs2
-rw-r--r--src/ir/annotations.rs11
-rw-r--r--tests/expectations/tests/derive-custom.rs97
-rw-r--r--tests/headers/derive-custom.h28
4 files changed, 138 insertions, 0 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 073745b1..9405f11b 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1764,6 +1764,8 @@ impl CodeGenerator for CompInfo {
derives.push("Eq");
}
+ derives.extend(item.annotations().derives().iter().map(String::as_str));
+
if !derives.is_empty() {
attributes.push(attributes::derives(&derives))
}
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
index bc57b555..654e1686 100644
--- a/src/ir/annotations.rs
+++ b/src/ir/annotations.rs
@@ -58,6 +58,8 @@ pub struct Annotations {
/// In that case, bindgen will generate a constant for `Bar` instead of
/// `Baz`.
constify_enum_variant: bool,
+ /// List of explicit derives for this type.
+ derives: Vec<String>,
}
fn parse_accessor(s: &str) -> FieldAccessorKind {
@@ -79,6 +81,7 @@ impl Default for Annotations {
private_fields: None,
accessor_kind: None,
constify_enum_variant: false,
+ derives: vec![],
}
}
}
@@ -130,6 +133,11 @@ impl Annotations {
self.use_instead_of.as_ref().map(|s| &**s)
}
+ /// The list of derives that have been specified in this annotation.
+ pub fn derives(&self) -> &[String] {
+ &self.derives
+ }
+
/// Should we avoid implementing the `Copy` trait?
pub fn disallow_copy(&self) -> bool {
self.disallow_copy
@@ -165,6 +173,9 @@ impl Annotations {
attr.value.split("::").map(Into::into).collect(),
)
}
+ "derive" => {
+ self.derives.push(attr.value)
+ }
"private" => {
self.private_fields = Some(attr.value != "false")
}
diff --git a/tests/expectations/tests/derive-custom.rs b/tests/expectations/tests/derive-custom.rs
new file mode 100644
index 00000000..1184e435
--- /dev/null
+++ b/tests/expectations/tests/derive-custom.rs
@@ -0,0 +1,97 @@
+/* automatically generated by rust-bindgen */
+
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+/// <div rustbindgen derive="Debug"></div>
+#[repr(C)]
+#[derive(Default, Debug)]
+pub struct my_type {
+ pub a: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_my_type() {
+ assert_eq!(
+ ::std::mem::size_of::<my_type>(),
+ 4usize,
+ concat!("Size of: ", stringify!(my_type))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<my_type>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(my_type))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<my_type>())).a as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(my_type),
+ "::",
+ stringify!(a)
+ )
+ );
+}
+/// <div rustbindgen derive="Debug"></div>
+/// <div rustbindgen derive="Clone"></div>
+#[repr(C)]
+#[derive(Default, Debug, Clone)]
+pub struct my_type2 {
+ pub a: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_my_type2() {
+ assert_eq!(
+ ::std::mem::size_of::<my_type2>(),
+ 4usize,
+ concat!("Size of: ", stringify!(my_type2))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<my_type2>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(my_type2))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<my_type2>())).a as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(my_type2),
+ "::",
+ stringify!(a)
+ )
+ );
+}
+/// <div rustbindgen derive="Debug" derive="Clone"></div>
+#[repr(C)]
+#[derive(Default, Debug, Clone)]
+pub struct my_type3 {
+ pub a: ::std::os::raw::c_ulong,
+}
+#[test]
+fn bindgen_test_layout_my_type3() {
+ assert_eq!(
+ ::std::mem::size_of::<my_type3>(),
+ 8usize,
+ concat!("Size of: ", stringify!(my_type3))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<my_type3>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(my_type3))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<my_type3>())).a as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(my_type3),
+ "::",
+ stringify!(a)
+ )
+ );
+}
diff --git a/tests/headers/derive-custom.h b/tests/headers/derive-custom.h
new file mode 100644
index 00000000..83f2ce08
--- /dev/null
+++ b/tests/headers/derive-custom.h
@@ -0,0 +1,28 @@
+// bindgen-flags: --no-derive-debug --no-derive-copy --default-enum-style rust
+
+/** <div rustbindgen derive="Debug"></div> */
+struct my_type;
+
+/** <div rustbindgen derive="Clone"></div> */
+struct my_type;
+
+struct my_type {
+ int a;
+};
+
+/**
+ * <div rustbindgen derive="Debug"></div>
+ * <div rustbindgen derive="Clone"></div>
+ */
+struct my_type2;
+
+struct my_type2 {
+ unsigned a;
+};
+
+/**
+ * <div rustbindgen derive="Debug" derive="Clone"></div>
+ */
+struct my_type3 {
+ unsigned long a;
+};