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