From 3f0a0db9e474ee6097a18246ce41ec04e75b0db6 Mon Sep 17 00:00:00 2001 From: Eric Seppanen Date: Wed, 2 Jun 2021 18:17:15 -0700 Subject: [PATCH 1/2] add custom derives callback This callback allows us to specify arbitrary derive attributes for each named struct. This is useful for adding things that can't easily be implemented separately, such as `serde::Deserialize` or `zerocopy::FromBytes`. --- src/callbacks.rs | 8 ++++++++ src/codegen/mod.rs | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/callbacks.rs b/src/callbacks.rs index e288af4341..9b34544947 100644 --- a/src/callbacks.rs +++ b/src/callbacks.rs @@ -95,4 +95,12 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe { ) -> Option { None } + + /// Provide a list of custom derive attributes. + /// + /// If no additional attributes are wanted, this function should return an + /// empty `Vec`. + fn add_derives(&self, _name: &str) -> Vec { + vec![] + } } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6f8a451a2a..4ae8050564 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1997,6 +1997,15 @@ impl CodeGenerator for CompInfo { let mut derives: Vec<_> = derivable_traits.into(); derives.extend(item.annotations().derives().iter().map(String::as_str)); + // The custom derives callback may return a list of derive attributes; + // add them to the end of the list. + let custom_derives; + if let Some(cb) = &ctx.options().parse_callbacks { + custom_derives = cb.add_derives(&canonical_name); + // In most cases this will be a no-op, since custom_derives will be empty. + derives.extend(custom_derives.iter().map(|s| s.as_str())); + }; + if !derives.is_empty() { attributes.push(attributes::derives(&derives)) } From 78d5dba3dac7e7be49a114c3617ab7cea7037509 Mon Sep 17 00:00:00 2001 From: Eric Seppanen Date: Sun, 6 Jun 2021 15:10:34 -0700 Subject: [PATCH 2/2] add test for add_derives This test derives PartialEq for the Test struct, and then attempts to use that by calling assert_ne! on two Test instances. If the derive callback doesn't work, no PartialEq will be present and the test will fail to compile. --- bindgen-integration/build.rs | 11 +++++++++++ bindgen-integration/src/lib.rs | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index b28dcee577..fa0246c460 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -119,6 +119,17 @@ impl ParseCallbacks for MacroCallback { } } } + + // Test the "custom derives" capability by adding `PartialEq` to the `Test` struct. + fn add_derives(&self, name: &str) -> Vec { + if name == "Test" { + vec![ + "PartialEq".into(), + ] + } else { + vec![] + } + } } impl Drop for MacroCallback { diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 4b288afdc9..f56e72597d 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -267,3 +267,12 @@ fn test_homogeneous_aggregate_float_union() { assert_eq!([1., 2., 3., 4.], coord.v) } } + +#[test] +fn test_custom_derive() { + // The `add_derives` callback should have added `#[derive(PartialEq)]` + // to the `Test` struct. If it didn't, this will fail to compile. + let test1 = unsafe { bindings::Test::new(5) }; + let test2 = unsafe { bindings::Test::new(6) }; + assert_ne!(test1, test2); +}