]> git.proxmox.com Git - rustc.git/blob - src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / test / run-pass / structs-enums / enum-non-c-like-repr-c.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // run-pass
12 // This test deserializes an enum in-place by transmuting to a union that
13 // should have the same layout, and manipulating the tag and payloads
14 // independently. This verifies that `repr(some_int)` has a stable representation,
15 // and that we don't miscompile these kinds of manipulations.
16
17 use std::time::Duration;
18 use std::mem;
19
20 #[repr(C)]
21 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
22 enum MyEnum {
23 A(u32), // Single primitive value
24 B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
25 C, // Empty
26 D(Option<u32>), // Contains an enum
27 E(Duration), // Contains a struct
28 }
29
30 #[repr(C)]
31 struct MyEnumRepr {
32 tag: MyEnumTag,
33 payload: MyEnumPayload,
34 }
35
36 #[repr(C)]
37 #[allow(non_snake_case)]
38 union MyEnumPayload {
39 A: MyEnumVariantA,
40 B: MyEnumVariantB,
41 D: MyEnumVariantD,
42 E: MyEnumVariantE,
43 }
44
45 #[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
46 #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
47 #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 }
48 #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
49 #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
50
51 fn main() {
52 let result: Vec<Result<MyEnum, ()>> = vec![
53 Ok(MyEnum::A(17)),
54 Ok(MyEnum::B { x: 206, y: 1145 }),
55 Ok(MyEnum::C),
56 Err(()),
57 Ok(MyEnum::D(Some(407))),
58 Ok(MyEnum::D(None)),
59 Ok(MyEnum::E(Duration::from_secs(100))),
60 Err(()),
61 ];
62
63 // Binary serialized version of the above (little-endian)
64 let input: Vec<u8> = vec![
65 0, 17, 0, 0, 0,
66 1, 206, 121, 4,
67 2,
68 8, /* invalid tag value */
69 3, 0, 151, 1, 0, 0,
70 3, 1,
71 4, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, /* incomplete value */
73 ];
74
75 let mut output = vec![];
76 let mut buf = &input[..];
77
78 unsafe {
79 // This should be safe, because we don't match on it unless it's fully formed,
80 // and it doesn't have a destructor.
81 let mut dest: MyEnum = mem::uninitialized();
82 while buf.len() > 0 {
83 match parse_my_enum(&mut dest, &mut buf) {
84 Ok(()) => output.push(Ok(dest)),
85 Err(()) => output.push(Err(())),
86 }
87 }
88 }
89
90 assert_eq!(output, result);
91 }
92
93 fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
94 unsafe {
95 // Should be correct to do this transmute.
96 let dest: &'a mut MyEnumRepr = mem::transmute(dest);
97 let tag = read_u8(buf)?;
98
99 dest.tag = match tag {
100 0 => MyEnumTag::A,
101 1 => MyEnumTag::B,
102 2 => MyEnumTag::C,
103 3 => MyEnumTag::D,
104 4 => MyEnumTag::E,
105 _ => return Err(()),
106 };
107
108 match dest.tag {
109 MyEnumTag::A => {
110 dest.payload.A.0 = read_u32_le(buf)?;
111 }
112 MyEnumTag::B => {
113 dest.payload.B.x = read_u8(buf)?;
114 dest.payload.B.y = read_u16_le(buf)? as i16;
115 }
116 MyEnumTag::C => {
117 /* do nothing */
118 }
119 MyEnumTag::D => {
120 let is_some = read_u8(buf)? == 0;
121 if is_some {
122 dest.payload.D.0 = Some(read_u32_le(buf)?);
123 } else {
124 dest.payload.D.0 = None;
125 }
126 }
127 MyEnumTag::E => {
128 let secs = read_u64_le(buf)?;
129 let nanos = read_u32_le(buf)?;
130 dest.payload.E.0 = Duration::new(secs, nanos);
131 }
132 }
133 Ok(())
134 }
135 }
136
137
138
139 // reader helpers
140
141 fn read_u64_le(buf: &mut &[u8]) -> Result<u64, ()> {
142 if buf.len() < 8 { return Err(()) }
143 let val = (buf[0] as u64) << 0
144 | (buf[1] as u64) << 8
145 | (buf[2] as u64) << 16
146 | (buf[3] as u64) << 24
147 | (buf[4] as u64) << 32
148 | (buf[5] as u64) << 40
149 | (buf[6] as u64) << 48
150 | (buf[7] as u64) << 56;
151 *buf = &buf[8..];
152 Ok(val)
153 }
154
155 fn read_u32_le(buf: &mut &[u8]) -> Result<u32, ()> {
156 if buf.len() < 4 { return Err(()) }
157 let val = (buf[0] as u32) << 0
158 | (buf[1] as u32) << 8
159 | (buf[2] as u32) << 16
160 | (buf[3] as u32) << 24;
161 *buf = &buf[4..];
162 Ok(val)
163 }
164
165 fn read_u16_le(buf: &mut &[u8]) -> Result<u16, ()> {
166 if buf.len() < 2 { return Err(()) }
167 let val = (buf[0] as u16) << 0
168 | (buf[1] as u16) << 8;
169 *buf = &buf[2..];
170 Ok(val)
171 }
172
173 fn read_u8(buf: &mut &[u8]) -> Result<u8, ()> {
174 if buf.len() < 1 { return Err(()) }
175 let val = buf[0];
176 *buf = &buf[1..];
177 Ok(val)
178 }