Based on the comment by Stargateur you can use some repr(C) struct and union combinations. Due to some limitations on union we require the underlying types to implement Copy.
#[repr(C)]
union COptionEnum<T>
where
T: Copy,
{
value: T,
none: (),
}
#[repr(C)]
struct COption<T>
where
T: Copy,
{
discriminant: u32,
value: COptionEnum<T>,
}
However these are not particularly ergonomic, so to ease the pain, you can provide conversions to and from Option. These look like this:
impl<T> From<Option<T>> for COption<T>
where
T: Copy,
{
fn from(v: Option<T>) -> COption<T> {
match v {
None => COption {
discriminant: 0,
value: COptionEnum { none: () },
},
Some(v) => COption {
discriminant: 1,
value: COptionEnum { value: v },
},
}
}
}
impl<T> From<COption<T>> for Option<T>
where
T: Copy,
{
fn from(v: COption<T>) -> Option<T> {
match v.discriminant {
0 => None,
1 => Some(unsafe { v.value.value }),
_ => panic!("Invalid COption"),
}
}
}
Finally, you can use these in a relatively painless manner.
#[repr(C)]
#[derive(Copy, Clone)]
struct AType {
a: i32,
b: u64,
}
fn main() {
let v1 = Some(AType { a: 1, b: 2 });
let cv1: COption<AType> = v1.into();
let w1: Option<AType> = cv1.into();
}
A complete copy is in the playground