Pass Str in PtrLen representation
MSVC is hesitant about passing private fields in an extern "C" signature.
Repro:
struct Str1 {
const char *ptr;
size_t len;
};
struct Str2 {
private:
const char *ptr;
size_t len;
};
extern "C" {
Str1 str1();
Str2 str2();
}
Warning from MSVC v19.27:
warning C4190: 'str2' has C-linkage specified, but returns UDT 'Str2' which is incompatible with C
diff --git a/gen/src/write.rs b/gen/src/write.rs
index a06ab62..e3e9221 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -324,7 +324,7 @@
out.begin_block("namespace");
- if needs_trycatch || needs_rust_error {
+ if needs_trycatch || needs_rust_error || needs_rust_str && !out.header {
out.begin_block("namespace repr");
writeln!(out, "struct PtrLen final {{");
writeln!(out, " const void *ptr;");
@@ -333,7 +333,28 @@
out.end_block("namespace repr");
}
+ if needs_rust_str && !out.header {
+ out.next_section();
+ writeln!(out, "template <>");
+ writeln!(out, "class impl<Str> final {{");
+ writeln!(out, "public:");
+ writeln!(
+ out,
+ " static Str new_unchecked(repr::PtrLen repr) noexcept {{",
+ );
+ writeln!(out, " Str str;");
+ writeln!(out, " str.ptr = static_cast<const char *>(repr.ptr);");
+ writeln!(out, " str.len = repr.len;");
+ writeln!(out, " return str;");
+ writeln!(out, " }}");
+ writeln!(out, " static repr::PtrLen repr(Str str) noexcept {{");
+ writeln!(out, " return repr::PtrLen{{str.ptr, str.len}};");
+ writeln!(out, " }}");
+ writeln!(out, "}};");
+ }
+
if needs_rust_error {
+ out.next_section();
writeln!(out, "template <>");
writeln!(out, "class impl<Error> final {{");
writeln!(out, "public:");
@@ -619,6 +640,7 @@
}
match &efn.ret {
Some(Type::Ref(_)) => write!(out, "&"),
+ Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::impl<::rust::Str>::repr("),
Some(Type::SliceRefU8(_)) if !indirect_return => {
write!(out, "::rust::Slice<uint8_t>::Repr(")
}
@@ -638,6 +660,12 @@
} else if let Type::UniquePtr(_) = &arg.ty {
write_type(out, &arg.ty);
write!(out, "({})", arg.ident);
+ } else if let Type::Str(_) = arg.ty {
+ write!(
+ out,
+ "::rust::impl<::rust::Str>::new_unchecked({})",
+ arg.ident,
+ );
} else if arg.ty == RustString {
write!(
out,
@@ -658,7 +686,7 @@
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
- Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
+ Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
if indirect_return {
@@ -850,6 +878,7 @@
write!(out, "(");
}
Type::Ref(_) => write!(out, "*"),
+ Type::Str(_) => write!(out, "::rust::impl<::rust::Str>::new_unchecked("),
_ => {}
}
}
@@ -865,6 +894,7 @@
write!(out, ", ");
}
match &arg.ty {
+ Type::Str(_) => write!(out, "::rust::impl<::rust::Str>::repr("),
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr("),
ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
_ => {}
@@ -873,7 +903,7 @@
match &arg.ty {
Type::RustBox(_) => write!(out, ".into_raw()"),
Type::UniquePtr(_) => write!(out, ".release()"),
- Type::SliceRefU8(_) => write!(out, ")"),
+ Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"),
_ => {}
}
@@ -893,7 +923,7 @@
write!(out, ")");
if !indirect_return {
if let Some(ret) = &sig.ret {
- if let Type::RustBox(_) | Type::UniquePtr(_) = ret {
+ if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) = ret {
write!(out, ")");
}
}
@@ -964,6 +994,7 @@
write_type(out, &ty.inner);
write!(out, " *");
}
+ Some(Type::Str(_)) => write!(out, "::rust::repr::PtrLen "),
Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
Some(ty) if out.types.needs_indirect_abi(ty) => write!(out, "void "),
_ => write_return_type(out, ty),
@@ -976,6 +1007,7 @@
write_type_space(out, &ty.inner);
write!(out, "*");
}
+ Type::Str(_) => write!(out, "::rust::repr::PtrLen "),
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
_ => write_type_space(out, &arg.ty),
}