What the best strategy to deals with C Union FFI?


#1

Some C function that I use return a struct with union inside it. This struct is basically tagged union with the first field act as discriminant value and the second act as its content. Currently what I do is just write the C struct (Foo) and enum (FooEnum) like this:

use std::mem;

#[repr(C)]
#[derive(Debug)]
struct Bar{
    value: i64
}

#[repr(C)]
#[derive(Debug)]
struct Baz{
    value: i8
}

#[repr(C)]
#[derive(Debug)]
struct Foo{
    discriminant: i32,
    content: Bar // Bar is the largest variant
}

#[derive(Debug)]
enum FooEnum{
    Bar(Bar),
    Baz(Baz)
}

impl Foo {
    fn get_enum(&self) -> FooEnum{
        match self.discriminant {
            0 => FooEnum::Bar(Bar{value: unsafe{mem::transmute_copy(&self.content)}}),
            1 => FooEnum::Baz(Baz{value: unsafe{mem::transmute_copy(&self.content)}}),
            _ => unreachable!()
        }
    }
}


fn main(){
    let x = Foo{discriminant: 1, content: Bar{value: 9}};
    let y = x.get_enum();
    println!("x = {:?}", x); // y = Baz(Baz { value: 9 })
    println!("y = {:?}", y); // print "y = Baz(Baz { value: 9 })"
}

However, I not sure if this strategy is good or not.
I am curious about what the others do to solve this union problem because I have seen many c libraries use union to represent its value.

C Structure with its first field as discriminant:

C Union which encoded the discriminant as first field of each structs:


#2

If that is all you are using the discriminant for why not just make

struct Foo{
   content: FooEnum;
}

Or if that’s the only field do you even need the Foo struct at all? Rust allows you to implement methods for enum also. In general as pointed in the answer to my question here the strategy which I know use, and like more is to put the enum union as inside as possible in the structs.

Also is there a reason why Bar and Baz don’t derive Copy? Would make it nicer rather than using unsafe code, no?

PS: Ok I’ve just figured out why you need this (because its importing it from a C library), which I did not pay attention before. In that case I think what you are doing is fine. Shouldn’t post an answer before breakfast any more!