Repository: dtolnay/cxx (language: rust)

Issue:
Add ifdef around shared struct definitions
Currently the generated cc file and generated header file both contain unconditional definitions of shared structs, which fails to compile if the header gets included transitively into the cc file -- such as if one of the `include!` files in the #\[cxx::bridge\] invocation contains an `#include` of the generated header.

To support this pattern we should emit a matching `ifdef` around the shared structs in the generated cc file and generated header file.


Discussion / hints:

Fix patch:
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 88a0734fb..e088e2c0f 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -318,6 +318,7 @@ fn write_include_cxxbridge(out: &mut OutFile, apis: &[Api], types: &Types) {
 }
 
 fn write_struct(out: &mut OutFile, strct: &Struct) {
+    write_include_guard_start(out, &strct.ident);
     for line in strct.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
@@ -328,6 +329,7 @@ fn write_struct(out: &mut OutFile, strct: &Struct) {
         writeln!(out, "{};", field.ident);
     }
     writeln!(out, "}};");
+    write_include_guard_end(out, &strct.ident);
 }
 
 fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
@@ -338,7 +340,31 @@ fn write_struct_using(out: &mut OutFile, ident: &Ident) {
     writeln!(out, "using {} = {};", ident, ident);
 }
 
+const INCLUDE_GUARD_PREFIX: &'static str = "CXXBRIDGE03_TYPE_";
+
+fn write_include_guard_start(out: &mut OutFile, ident: &Ident) {
+    writeln!(
+        out,
+        "#ifndef {}{}{}",
+        INCLUDE_GUARD_PREFIX, out.namespace, ident
+    );
+    writeln!(
+        out,
+        "#define {}{}{}",
+        INCLUDE_GUARD_PREFIX, out.namespace, ident
+    );
+}
+
+fn write_include_guard_end(out: &mut OutFile, ident: &Ident) {
+    writeln!(
+        out,
+        "#endif // {}{}{}",
+        INCLUDE_GUARD_PREFIX, out.namespace, ident
+    );
+}
+
 fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: &[&ExternFn]) {
+    write_include_guard_start(out, &ety.ident);
     for line in ety.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
@@ -353,9 +379,11 @@ fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: &[&Ex
         writeln!(out, ";");
     }
     writeln!(out, "}};");
+    write_include_guard_end(out, &ety.ident);
 }
 
 fn write_enum(out: &mut OutFile, enm: &Enum) {
+    write_include_guard_start(out, &enm.ident);
     for line in enm.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
@@ -366,6 +394,7 @@ fn write_enum(out: &mut OutFile, enm: &Enum) {
         writeln!(out, "  {} = {},", variant.ident, variant.discriminant);
     }
     writeln!(out, "}};");
+    write_include_guard_end(out, &enm.ident);
 }
 
 fn check_enum(out: &mut OutFile, enm: &Enum) {


Test patch: