cxx
cxx copied to clipboard
Reusing simple structs in the bridge interface
We have a Rust API that we're trying to expose to C++. It has a ton of simple structs like this:
#[derive(Debug)]
pub struct LibVersion {
pub string: String,
pub package_hash: String,
pub major: u32,
pub minor: u32,
pub point: u32,
}
#[derive(Debug, Clone)]
pub struct CompilationTraceEvent {
pub cat: String,
pub dur: u64,
pub name: String,
pub ph: String,
pub pid: u32,
pub tid: u32,
pub ts: u64,
}
pub struct ItemType {
pub name: String,
pub size: u64,
pub source: ItemSource,
}
#[derive(Debug, Copy, Clone)]
pub enum ItemSource {
A,
B,
}
You get the idea. In order to expose these to C++ the obvious but annoying thing to do is to copy/paste them all into the mod ffi { and then tediously add From implementations. Obviously not ideal!
The second best solution that I can think of at the moment is to move everything into the ffi mod, and then we can add pub use ffi::LibVersion etc. which is much less tedious. I think this will work, but it seems like only Copy and Clone auto-derive traits are supported by the macro.
I assume the proc macro system only gives you the contents of the macro, so you could never do something like mod ffi { type LibVersion = super::LibVersion; } because then your proc macro has no idea what the fields of super::LibVersion are - is that right?
I'm not sure what the solution is here but it's definitely an annoying problem....
Has anyone figured out what to do in this situation? CXX seems awesome but we have a lot of structs with custom derives and have run into exactly the same problem here...
Update: As a workaround, I implemented the following patch. If you try to derive something that is not derivable in C++, this patch will still derive those traits for Rust, instead of giving up.
diff --git a/syntax/attrs.rs b/syntax/attrs.rs
index cb40295b..57e79b7b 100644
--- a/syntax/attrs.rs
+++ b/syntax/attrs.rs
@@ -65,9 +65,17 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
}
} else if attr.path.is_ident("derive") {
match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
- Ok(attr) => {
- if let Some(derives) = &mut parser.derives {
- derives.extend(attr);
+ Ok((attr_if_ok, ok)) => {
+ if ok {
+ if let Some(derives) = &mut parser.derives {
+ derives.extend(attr_if_ok);
+ continue;
+ }
+ } else {
+ // If the derive attribute is not valid, we pass it through. Then, it will be available
+ // in Rust but not in C++. This is often fine.
+ // For the traits that you do want to derive in C++, provide them in a separate #[derive(...)]
+ passthrough_attrs.push(attr);
continue;
}
}
@@ -208,10 +216,11 @@ fn parse_doc_attribute(input: ParseStream) -> Result<DocAttribute> {
}
}
-fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
+fn parse_derive_attribute(_cx: &mut Errors, input: ParseStream) -> Result<(Vec<Derive>, bool)> {
let paths = input.parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?;
let mut derives = Vec::new();
+ let mut ok = true;
for path in paths {
if let Some(ident) = path.get_ident() {
if let Some(derive) = Derive::from(ident) {
@@ -219,9 +228,9 @@ fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Der
continue;
}
}
- cx.error(path, "unsupported derive");
+ ok = false;
}
- Ok(derives)
+ Ok((derives, ok))
}
fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
@Timmmm Did you ever figure out a workaround for this?
I don't think so, sorry. :-/
The discussion under #1077 lays out the supported options for reusing simple structs in the bridge interface.