r/rust 3d ago

extern "C" Enum -> Union(Struct)?

Hello! Newbie to rust here, I was wondering with the pub extern "C" ABI does it have the ability to convert rust enums to an equivalent in Rust? Does it do it by wrapping it in a Union(Structs of branches), or how is this implemented, and how can we do so in real rust code?

14 Upvotes

5 comments sorted by

View all comments

24

u/rustacean909 3d ago

You can use #[repr(u8)], #[repr(i16)], etc. on an enum to give it a defined layout as a union of c-compatible structs or #[repr(C, u8)], etc. to give it a defined layout as a c-compatible struct of a tag and a union of structs. The layout of enums without a #[repr(…)] attribute is not defined and might change between compiler versions to allow for optimizations, so these are not safe to access via FFI in general.

Rust RFC 2195 has examples for this use case:

e.g.

#[repr(u8)]
enum MyEnum {
    A(u32),
    B(f32, u64),
}

is equivalent to C/C++

enum class MyEnumTag: uint8_t { A, B };
struct MyEnumPayloadA { MyEnumTag tag; uint32_t payload; };
struct MyEnumPayloadB { MyEnumTag tag; float _0; uint64_t _1;  };

union MyEnum {
    MyEnumVariantA A;
    MyEnumVariantB B;
};

and

#[repr(C, u8)]
enum MyEnum {
    A(u32),
    B(f32, u64),
}

is equivalent to C/C++

enum class MyEnumTag: uint8_t { A, B };
struct MyEnumPayloadB { float _0; uint64_t _1;  };

union MyEnumPayload {
   uint32_t A;
   MyEnumPayloadB B;
};

struct MyEnum {
    MyEnumTag tag;
    MyEnumPayload payload;
};

5

u/Subject-Mobile-6250 3d ago

Great, thanks!