How to derive custom traits for struct definitions generated by bindgen?

Hello,

I'm looking for a painless way to use a custom trait derivation on structs generated from a C header via bindgen. Specifically, I want to derive serde's Serialize and Deserialize traits on a simple C struct.

I've set up the scaffolding mirroring the official tutorial almost directly, including an unmodified build.rs, a header wrapper, and a lib.rs that looks like this:

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

And within bindings.rs there is a struct:

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExampleStruct {
    pub example_value: ::std::os::raw::c_short,
}

I'd love to be able to swap out the derive line for #[derive(Copy, Clone, Serialize, Deserialize)]. I suppose I could do this in the build script before writing bindings.rs by looking for existing derive lines and swapping them with the modified version, but I'm hoping a cleaner solution exists.

Can anybody offer any help or suggestions? I feel like I may be missing something simple here.

Bindgen doesn't yet have a built-in way to do this. See Allow custom derives and attributes · Issue #1089 · rust-lang/rust-bindgen · GitHub

Here's an example of an existing project that does this: Add feature flag for deriving serde macros. The default is off. by skywhale · Pull Request #4 · tonarino/webrtc-audio-processing · GitHub

1 Like

Thanks for linking to the parent issue on the bindgen repo!

let new_contents = format!(
    "use serde::{{Serialize, Deserialize}};\n{}",
    Regex::new(r"#\s*\[\s*derive\s*\((?P<d>[^)]+)\)\s*\]\s*pub\s*(?P<s>struct|enum)")?
        .replace_all(&contents, "#[derive($d, Serialize, Deserialize)] pub $s")
);

I was hoping to avoid doing something like this (from the webrtc-audio-processing example), but c'est la vie.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.