cbindgen
cbindgen copied to clipboard
Rust Option to C
(working solution at the end of this post)
Hello, I managed to get an enum to represent an option and port it to C side, but I realised something that I can't understand, maybe you can help me ?
First I tried :
//LIB.RS
#[repr(C)] //Edit: also tried repr(u16)
#[derive(Debug, Clone, Copy, PartialEq)]
// Cbindgen tweak to represent an option
pub enum OptionU16 {
Some(u16),
None
}
Which generate :
///LIB.HPP
struct OptionU16 {
enum class Tag {
Some,
None,
};
struct Some_Body {
Some _0;
};
Tag tag;
union {
Some_Body some;
};
};
At first attempt, everything was okay :
//MAIN.CPP
OptionU16 w;
w.tag=OptionU16::Tag::Some;
w.some._0=10;
But after that, I tried to get the enum variant from rust side :
// LIB.RS
#[no_mangle]
pub extern "C" fn test_get_some_10() -> OptionU16 {
OptionU16::Some(42)
}
// MAIN.CPP
OptionU16 foo = test_get_some_10();
At this point, foo.tag = foo.some._0 = 32767 (Max value for a U16) Can someone explain to me why ?
If someone need a working solution, I found this to be okay :
// LIB.RS
#[repr(C)]
pub struct OptU16 {
tag: OptU16Tag,
payload: OptU16Payload,
}
#[repr(C)]
pub enum OptU16Tag { SOME, NONE }
#[repr(C)]
pub union OptU16Payload {
SOME: u16,
NONE:()
}
Hmm, weird... Is some of the transformations here not valid for some alignment / not what https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md specifies?
Or is it a rustc bug? I'd have to check carefully.
cc @Gankra
I'm having trouble reproducing this. Can you provide a standalone project I can build, and/or specify what platform you're targeting?
Also interestingly in the bare repr(C) case our codegen is probably slightly incorrect. repr(C) is "C enum sized", which is platform/implementation-defined thing that Rust has to vaguely guess at (usually int iirc). But a C++ enum class is guaranteed to be int.
Hi,
Sorry for my very late answer... I'm under MacOS right now, but this code should run on a x64 upboard + debian
Please see this repo for a test program.
I had a similar problem for C structs defined in a shared C library and allocated as an option in Rust: Option<MyStructFromFFI> which is leading to undefined (non-C) memory alignment for MyStructFromFFI if used by the shared C libary. I got it working by using std::mem::MaybeUninit instead of std::option::Option.
Note: I was using bindgen instead of cbindgen, but the problem seems similar.