Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

FFI and union #5492

Open
sanxiyn opened this Issue · 19 comments
@sanxiyn
Collaborator

How would one call C functions involving union with Rust FFI?

SpiderMonkey's jsval is one example.

@thestinger

There could be unsafe enum with the layout defined to be the same as C for interoperability. The only other way to deal with it would be finding the alignof and sizeof of the union in C for each platform and then translating that to Rust.

@sanxiyn
Collaborator

Referencing Aatch/rust-xcb#2.

@yichoi

referencing servo/servo#398

referencing servo/rust-mozjs#9

@Aatch
Collaborator

The unsafe enum idea appeals to me, since I thought about it as an option when trying to solve the union issue in rust-xcb, but decided that relying on the representation of enums was too "hacky" and fragile.

@pnkfelix
Collaborator

brson mentions in the description for #6346 that a "macro based solution" would be appropriate here, though I do not current know what that would entail. (It sounds to me like a potential alternative to the changes to the grammar to add unsafe enum that have been discussed here.)

@pnkfelix
Collaborator

Nominating for milestone 3, feature complete.

@cmr
Collaborator

I don't think a "macro-based solution" would be appropriate, as you need to restrict the valid range of values at the site of usage, which macros cannot do.

@graydon

An attribute on an enum that makes it have no discriminant and makes any match on the variant-part succeed, should be sufficient. Not pretty but neither are C union semantics.

@graydon

accepted for feature-complete milestone

@Skrylar

I ran in to this problem recently as well; Allegro makes use of Unions for passing events around in C, which turns out to be a pain to deal with in Rust.

@mzabaluev mzabaluev referenced this issue in gi-rust/grust
Open

Need a way to represent union values #11

@pnkfelix
Collaborator

We do want to solve this problem eventually, but it need not block 1.0. Assigning P-low.

@pnkfelix pnkfelix added P-low and removed P-high-untriaged labels
@alxkolm

What status?

@alexchandel

What's the recommended way to do FFI-compatible unions?

@jdm
Collaborator

I believe structs containing a field which is at least as big as the largest type the union can represent and manual transmutes is the state of the art right now.

@mzabaluev

I believe structs containing a field which is at least as big as the largest type the union can represent and manual transmutes is the state of the art right now.

Make sure you get the alignments right. The struct should have #[repr(C)] and the field posing as the union (or the inner type, in case the newtype struct emulates the union itself) has the alignment of the most-aligned variant.

@alexchandel

@jdm Even when variants are different sizes? transmute errors when T and U have different sizes, and transmute_copy is just as dangerous since it copies sizeof(U) bytes, triggering "undefined behavior".

@mzabaluev

Also, the overall size of the union is a multiple of the alignment of its most-aligned variant. This union has the size of 8:

union A {
    int32_t intval;
    char chars[5];
};

Which would require a Rust representation like:

#[repr(C)]
struct A {
    union_data: [i32; 2]
}

So yes, representing unions is not for the unwary.

@alexchandel

@mzabaluev For a C union like this:

struct INPUT {
  DWORD type;
  union {
    MOUSEINPUT    mi;
    KEYBDINPUT    ki;
    HARDWAREINPUT hi;
  };
};

I use a struct field rather bytes. It's easier because the size and alignment change between platforms, and you can't do [u8; size_of::<MOUSEINPUT>()]

#[repr(C)]
pub struct MOUSEINPUT { ... }
#[repr(C)]
pub struct KEYBDINPUT { ... }
#[repr(C)]
pub struct HARDWAREINPUT { ... }

#[repr(C)]
pub struct INPUT {
    pub tag_: DWORD,
    pub union_: MOUSEINPUT, // MOUSEINPUT largest and most aligned
}
@mzabaluev

@alexchandel Good when it works, but sometimes the largest variant is not the most aligned, like in my example above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.