randomPoison / cs-bindgen

Experiment in using Rust to build a library that can be loaded by Unity across multiple platforms
4 stars 0 forks source link

Support marshaling data-carrying enums #40

Closed randomPoison closed 4 years ago

randomPoison commented 4 years ago

This PR adds full support for marshaling data-carrying enums by value, e.g.:

#[cs_bindgen]
pub enum MyEnum {
    Foo(i32),
    Bar {
        name: String,
        value: i32,
    },
    Baz,
}

I changed type marshaling logic on the C# side to use a generic solution based on overloads of __FromRaw and __IntoRaw methods on the __bindings class. This makes it possible to easily do deep structural conversion of types while minimizing complexity in the code generation logic. In order to make this work, though, we now need to generate a bespoke "raw" representation for every exported type, even when the ABI representation on the Rust side is a primitive type.

We're using [StructLayout(LayoutKind.Explicit)] and [FieldOffset(0)] in the hopes that this will have a similar effect to #[repr(transparent)] in Rust and make the marshaling sound, however we'll likely need to revisit it at some point and make sure everything is guaranteed to work as intended. This also applies for bools, which now have a RustBool raw representation, and handle types, which have a raw struct that is a wrapper around a void*.

I've also had to remove the generic RawEnum<> helper struct and instead generate a bespoke raw enum representation for each exported data-carrying enum. This was necessary because generic types can't be be marshaled by C#, and it had the added benefit of further simplifying the code generation for raw bindings.