Description
Hello everyone!
I am having an issue understanding how to share an Enum, where some variants holds a Box, through FFI boundary.
The Enum looks like this:
#[derive(Debug)]
#[repr(C)]
pub enum SchemeType {
Ip,
Bytes,
Int,
Bool,
Array(Box<SchemeType>),
Map(Box<SchemeType>),
}
At the beginning I thought it would not possible to share this type with C directly, but then I found https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
So after reading that RFC, I thought that the C type equivalent type would be something like:
typedef enum {
SCHEME_TYPE_TAG_IP,
SCHEME_TYPE_TAG_BYTES,
SCHEME_TYPE_TAG_INT,
SCHEME_TYPE_TAG_BOOL,
SCHEME_TYPE_TAG_ARRAY,
SCHEME_TYPE_TAG_MAP,
} scheme_type_tag_t;
typedef struct {
scheme_type_tag_t tag;
void *data;
} scheme_type_t;
You can find the code here: marmeladema/rust-ffi-enum-box@8d61450
This did not worked well, and crashed in the test functions with Illegal instruction
.
I read this issue #52976 but its still not clear at all if Box<T>
can be represented directly with a pointer. Its currently not #[repr(transparent)]
so I guess until it is, it cannot safely be done.
After trying different things, i figured that adding 8 bytes padding to the end of scheme_type_t
worked, at least on x86_64
: marmeladema/rust-ffi-enum-box@2bc030e
But this does not work at all on aarch64
.
The question is then, how should I approach this issue?
I figured the best way might be add a FFI-compatible SchemeTypeFFI
wrapper, (storing a raw pointer instead of a Box<T>
and convert back and forth from and to real Rust SchemeType
type:
pub enum SchemeTypeFFI {
Ip,
Bytes,
Int,
Bool,
Array(*mut SchemeType),
Map(*mut SchemeType),
}
Thank you in advance for your help!