Splicing in my comment from a related RFC:
- Add a built-in type
UnsafeUnion<A, B>.
- This is essentially like
unions in C: a type compatible with the size and alignment of both A and B. So sizeof(UnsafeUnion<A, B>) = max(sizeof(A), sizeof(B)), and alignof(UnsafeUnion<A, B>) = lcm(alignof(A), alignof(B)).
- Unlike C, it doesn't have fields, rather "construction" and "deconstruction" both simply happen using
transmute(). So transmute::<A, UnsafeUnion<A, B>>, transmute::<B, UnsafeUnion<A, B>>, transmute::<UnsafeUnion<A, B>, A>, and transmute::<UnsafeUnion<A, B>, B> all have well-defined behavior, in basically the same circumstances as in C. (This means that the input and output of transmute would not have the same size/alignment in these cases. I don't know whether this is an issue, provided that they are both known.)
transmutes of pointers/references, on the other hand, should only be valid in one direction: e.g. you can legally transmute &UnsafeUnion<A, B> to &A, but not vice versa.
- Because the representation of
UnsafeUnions is idempotent: repr(UnsafeUnion<A, A>) = repr(A), commutative: repr(UnsafeUnion<A, B>) = repr(UnsafeUnion<B, A>), and associative: repr(UnsafeUnion<A, UnsafeUnion<B, C>>) = repr(UnsafeUnion<UnsafeUnion<A, B>, C>), larger unions can simply be composed from the binary one. The use of transmute for {,de}construction is also completely impervious to this nesting. We could then also potentially provide synonyms like type UnsafeUnion3<A, B, C> = UnsafeUnion<A, UnsafeUnion<B, C>> for convenience.
- It should also be layout-compatible with C, and so should be usable to represent C unions in the FFI.
This would primarily be for (a) unsafe code and (b) interfacing with C.
Splicing in my comment from a related RFC:
UnsafeUnion<A, B>.unions in C: a type compatible with the size and alignment of bothAandB. So sizeof(UnsafeUnion<A, B>) = max(sizeof(A), sizeof(B)), and alignof(UnsafeUnion<A, B>) = lcm(alignof(A), alignof(B)).transmute(). Sotransmute::<A, UnsafeUnion<A, B>>,transmute::<B, UnsafeUnion<A, B>>,transmute::<UnsafeUnion<A, B>, A>, andtransmute::<UnsafeUnion<A, B>, B>all have well-defined behavior, in basically the same circumstances as in C. (This means that the input and output oftransmutewould not have the same size/alignment in these cases. I don't know whether this is an issue, provided that they are both known.)transmutes of pointers/references, on the other hand, should only be valid in one direction: e.g. you can legallytransmute&UnsafeUnion<A, B>to&A, but not vice versa.UnsafeUnions is idempotent: repr(UnsafeUnion<A, A>) = repr(A), commutative: repr(UnsafeUnion<A, B>) = repr(UnsafeUnion<B, A>), and associative: repr(UnsafeUnion<A, UnsafeUnion<B, C>>) = repr(UnsafeUnion<UnsafeUnion<A, B>, C>), larger unions can simply be composed from the binary one. The use oftransmutefor {,de}construction is also completely impervious to this nesting. We could then also potentially provide synonyms liketype UnsafeUnion3<A, B, C> = UnsafeUnion<A, UnsafeUnion<B, C>>for convenience.This would primarily be for (a) unsafe code and (b) interfacing with C.