|  | //@ run-pass | 
|  | // This test deserializes an enum in-place by transmuting to a union that | 
|  | // should have the same layout, and manipulating the tag and payloads | 
|  | // independently. This verifies that `repr(some_int)` has a stable representation, | 
|  | // and that we don't miscompile these kinds of manipulations. | 
|  |  | 
|  | use std::time::Duration; | 
|  | use std::mem; | 
|  |  | 
|  | #[repr(C)] | 
|  | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | 
|  | enum MyEnum { | 
|  | A(u32),                     // Single primitive value | 
|  | B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` | 
|  | // depend on tag being internal | 
|  | C,                          // Empty | 
|  | D(Option<u32>),             // Contains an enum | 
|  | E(Duration),                // Contains a struct | 
|  | } | 
|  |  | 
|  | #[repr(C)] | 
|  | struct MyEnumRepr { | 
|  | tag: MyEnumTag, | 
|  | payload: MyEnumPayload, | 
|  | } | 
|  |  | 
|  | #[repr(C)] | 
|  | #[allow(non_snake_case)] | 
|  | union MyEnumPayload { | 
|  | A: MyEnumVariantA, | 
|  | B: MyEnumVariantB, | 
|  | D: MyEnumVariantD, | 
|  | E: MyEnumVariantE, | 
|  | } | 
|  |  | 
|  | #[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E } | 
|  | #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32); | 
|  | #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 } | 
|  | #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>); | 
|  | #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration); | 
|  |  | 
|  | fn main() { | 
|  | let result: Vec<Result<MyEnum, ()>> = vec![ | 
|  | Ok(MyEnum::A(17)), | 
|  | Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), | 
|  | Ok(MyEnum::C), | 
|  | Err(()), | 
|  | Ok(MyEnum::D(Some(407))), | 
|  | Ok(MyEnum::D(None)), | 
|  | Ok(MyEnum::E(Duration::from_secs(100))), | 
|  | Err(()), | 
|  | ]; | 
|  |  | 
|  | // Binary serialized version of the above (little-endian) | 
|  | let input: Vec<u8> = vec![ | 
|  | 0,  17, 0, 0, 0, | 
|  | 1,  206,  121, 4,  78, | 
|  | 2, | 
|  | 8,  /* invalid tag value */ | 
|  | 3,  0,  151, 1, 0, 0, | 
|  | 3,  1, | 
|  | 4,  100, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0, | 
|  | 0,  /* incomplete value */ | 
|  | ]; | 
|  |  | 
|  | let mut output = vec![]; | 
|  | let mut buf = &input[..]; | 
|  |  | 
|  | unsafe { | 
|  | // This should be safe, because we don't match on it unless it's fully formed, | 
|  | // and it doesn't have a destructor. | 
|  | // | 
|  | // Furthermore, there are no types within MyEnum which cannot be initialized with zero, | 
|  | // specifically, though padding and such are present, there are no references or similar | 
|  | // types. | 
|  | let mut dest: MyEnum = mem::zeroed(); | 
|  | while buf.len() > 0 { | 
|  | match parse_my_enum(&mut dest, &mut buf) { | 
|  | Ok(()) => output.push(Ok(dest)), | 
|  | Err(()) => output.push(Err(())), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | assert_eq!(output, result); | 
|  | } | 
|  |  | 
|  | fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> { | 
|  | unsafe { | 
|  | // Should be correct to do this transmute. | 
|  | let dest: &'a mut MyEnumRepr = mem::transmute(dest); | 
|  | let tag = read_u8(buf)?; | 
|  |  | 
|  | dest.tag = match tag { | 
|  | 0 => MyEnumTag::A, | 
|  | 1 => MyEnumTag::B, | 
|  | 2 => MyEnumTag::C, | 
|  | 3 => MyEnumTag::D, | 
|  | 4 => MyEnumTag::E, | 
|  | _ => return Err(()), | 
|  | }; | 
|  |  | 
|  | match dest.tag { | 
|  | MyEnumTag::A => { | 
|  | dest.payload.A.0 = read_u32_le(buf)?; | 
|  | } | 
|  | MyEnumTag::B => { | 
|  | dest.payload.B.x = read_u8(buf)?; | 
|  | dest.payload.B.y = read_u16_le(buf)? as i16; | 
|  | dest.payload.B.z = read_u8(buf)?; | 
|  | } | 
|  | MyEnumTag::C => { | 
|  | /* do nothing */ | 
|  | } | 
|  | MyEnumTag::D => { | 
|  | let is_some = read_u8(buf)? == 0; | 
|  | if is_some { | 
|  | dest.payload.D.0 = Some(read_u32_le(buf)?); | 
|  | } else { | 
|  | dest.payload.D.0 = None; | 
|  | } | 
|  | } | 
|  | MyEnumTag::E => { | 
|  | let secs = read_u64_le(buf)?; | 
|  | let nanos = read_u32_le(buf)?; | 
|  | dest.payload.E.0 = Duration::new(secs, nanos); | 
|  | } | 
|  | } | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // reader helpers | 
|  |  | 
|  | fn read_u64_le(buf: &mut &[u8]) -> Result<u64, ()> { | 
|  | if buf.len() < 8 { return Err(()) } | 
|  | let val = (buf[0] as u64) << 0 | 
|  | | (buf[1] as u64) << 8 | 
|  | | (buf[2] as u64) << 16 | 
|  | | (buf[3] as u64) << 24 | 
|  | | (buf[4] as u64) << 32 | 
|  | | (buf[5] as u64) << 40 | 
|  | | (buf[6] as u64) << 48 | 
|  | | (buf[7] as u64) << 56; | 
|  | *buf = &buf[8..]; | 
|  | Ok(val) | 
|  | } | 
|  |  | 
|  | fn read_u32_le(buf: &mut &[u8]) -> Result<u32, ()> { | 
|  | if buf.len() < 4 { return Err(()) } | 
|  | let val = (buf[0] as u32) << 0 | 
|  | | (buf[1] as u32) << 8 | 
|  | | (buf[2] as u32) << 16 | 
|  | | (buf[3] as u32) << 24; | 
|  | *buf = &buf[4..]; | 
|  | Ok(val) | 
|  | } | 
|  |  | 
|  | fn read_u16_le(buf: &mut &[u8]) -> Result<u16, ()> { | 
|  | if buf.len() < 2 { return Err(()) } | 
|  | let val = (buf[0] as u16) << 0 | 
|  | | (buf[1] as u16) << 8; | 
|  | *buf = &buf[2..]; | 
|  | Ok(val) | 
|  | } | 
|  |  | 
|  | fn read_u8(buf: &mut &[u8]) -> Result<u8, ()> { | 
|  | if buf.len() < 1 { return Err(()) } | 
|  | let val = buf[0]; | 
|  | *buf = &buf[1..]; | 
|  | Ok(val) | 
|  | } |