1 #![allow(dead_code)]
2
3 use bytemuck::{
4 AnyBitPattern, CheckedBitPattern, Contiguous, NoUninit, Pod,
5 TransparentWrapper, Zeroable, checked::CheckedCastError,
6 };
7 use std::marker::{PhantomData, PhantomPinned};
8
9 #[derive(Copy, Clone, Pod, Zeroable)]
10 #[repr(C)]
11 struct Test {
12 a: u16,
13 b: u16,
14 }
15
16 #[derive(Pod, Zeroable)]
17 #[repr(C, packed)]
18 struct GenericPackedStruct<T: Pod> {
19 a: u32,
20 b: T,
21 c: u32,
22 }
23
24 impl<T: Pod> Clone for GenericPackedStruct<T> {
clone(&self) -> Self25 fn clone(&self) -> Self {
26 *self
27 }
28 }
29
30 impl<T: Pod> Copy for GenericPackedStruct<T> {}
31
32 #[derive(Pod, Zeroable)]
33 #[repr(C, packed(1))]
34 struct GenericPackedStructExplicitPackedAlignment<T: Pod> {
35 a: u32,
36 b: T,
37 c: u32,
38 }
39
40 impl<T: Pod> Clone for GenericPackedStructExplicitPackedAlignment<T> {
clone(&self) -> Self41 fn clone(&self) -> Self {
42 *self
43 }
44 }
45
46 impl<T: Pod> Copy for GenericPackedStructExplicitPackedAlignment<T> {}
47
48 #[derive(Zeroable)]
49 struct ZeroGeneric<T: bytemuck::Zeroable> {
50 a: T,
51 }
52
53 #[derive(Zeroable)]
54 #[repr(u8)]
55 enum ZeroEnum {
56 A = 0,
57 B = 1,
58 C = 2,
59 }
60
61 #[derive(TransparentWrapper)]
62 #[repr(transparent)]
63 struct TransparentSingle {
64 a: u16,
65 }
66
67 #[derive(TransparentWrapper)]
68 #[repr(transparent)]
69 #[transparent(u16)]
70 struct TransparentWithZeroSized<T> {
71 a: u16,
72 b: PhantomData<T>,
73 }
74
75 struct MyZst<T>(PhantomData<T>, [u8; 0], PhantomPinned);
76 unsafe impl<T> Zeroable for MyZst<T> {}
77
78 #[derive(TransparentWrapper)]
79 #[repr(transparent)]
80 #[transparent(u16)]
81 struct TransparentTupleWithCustomZeroSized<T>(u16, MyZst<T>);
82
83 #[repr(u8)]
84 #[derive(Clone, Copy, Contiguous)]
85 enum ContiguousWithValues {
86 A = 0,
87 B = 1,
88 C = 2,
89 D = 3,
90 E = 4,
91 }
92
93 #[repr(i8)]
94 #[derive(Clone, Copy, Contiguous)]
95 enum ContiguousWithImplicitValues {
96 A = -10,
97 B,
98 C,
99 D,
100 E,
101 }
102
103 #[derive(Copy, Clone, NoUninit)]
104 #[repr(C)]
105 struct NoUninitTest {
106 a: u16,
107 b: u16,
108 }
109
110 #[derive(Copy, Clone, AnyBitPattern)]
111 #[repr(C)]
112 union UnionTestAnyBitPattern {
113 a: u8,
114 b: u16,
115 }
116
117 #[repr(u8)]
118 #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)]
119 enum CheckedBitPatternEnumWithValues {
120 A = 0,
121 B = 1,
122 C = 2,
123 D = 3,
124 E = 4,
125 }
126
127 #[repr(i8)]
128 #[derive(Clone, Copy, NoUninit, CheckedBitPattern)]
129 enum CheckedBitPatternEnumWithImplicitValues {
130 A = -10,
131 B,
132 C,
133 D,
134 E,
135 }
136
137 #[repr(u8)]
138 #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)]
139 enum CheckedBitPatternEnumNonContiguous {
140 A = 1,
141 B = 8,
142 C = 2,
143 D = 3,
144 E = 56,
145 }
146
147 #[repr(u8)]
148 #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)]
149 enum CheckedBitPatternEnumByteLit {
150 A = b'A',
151 B = b'B',
152 C = b'C',
153 D = b'D',
154 E = b'E',
155 }
156
157 #[derive(Debug, Copy, Clone, NoUninit, CheckedBitPattern, PartialEq, Eq)]
158 #[repr(C)]
159 struct CheckedBitPatternStruct {
160 a: u8,
161 b: CheckedBitPatternEnumNonContiguous,
162 }
163
164 #[derive(Debug, Copy, Clone, AnyBitPattern, PartialEq, Eq)]
165 #[repr(C)]
166 struct AnyBitPatternTest<A: AnyBitPattern, B: AnyBitPattern> {
167 a: A,
168 b: B,
169 }
170
171 #[derive(Clone, Copy, CheckedBitPattern)]
172 #[repr(C, align(8))]
173 struct CheckedBitPatternAlignedStruct {
174 a: u16,
175 }
176
177 #[derive(Debug, Clone, Copy, CheckedBitPattern, PartialEq, Eq)]
178 #[repr(C)]
179 enum CheckedBitPatternCDefaultDiscriminantEnumWithFields {
180 A(u64),
181 B { c: u64 },
182 }
183
184 #[derive(Debug, Clone, Copy, CheckedBitPattern, PartialEq, Eq)]
185 #[repr(C, u8)]
186 enum CheckedBitPatternCEnumWithFields {
187 A(u32),
188 B { c: u32 },
189 }
190
191 #[derive(Debug, Clone, Copy, CheckedBitPattern, PartialEq, Eq)]
192 #[repr(u8)]
193 enum CheckedBitPatternIntEnumWithFields {
194 A(u8),
195 B { c: u32 },
196 }
197
198 #[derive(Debug, Clone, Copy, CheckedBitPattern, PartialEq, Eq)]
199 #[repr(transparent)]
200 enum CheckedBitPatternTransparentEnumWithFields {
201 A { b: u32 },
202 }
203
204 // size 24, align 8.
205 // first byte always the u8 discriminant, then 7 bytes of padding until the payload union since the align of the payload
206 // is the greatest of the align of all the variants, which is 8 (from CheckedBitPatternCDefaultDiscriminantEnumWithFields)
207 #[derive(Debug, Clone, Copy, CheckedBitPattern, PartialEq, Eq)]
208 #[repr(C, u8)]
209 enum CheckedBitPatternEnumNested {
210 A(CheckedBitPatternCEnumWithFields),
211 B(CheckedBitPatternCDefaultDiscriminantEnumWithFields),
212 }
213
214 /// ```compile_fail
215 /// use bytemuck::{Pod, Zeroable};
216 ///
217 /// #[derive(Pod, Zeroable)]
218 /// #[repr(transparent)]
219 /// struct TransparentSingle<T>(T);
220 ///
221 /// struct NotPod(u32);
222 ///
223 /// let _: u32 = bytemuck::cast(TransparentSingle(NotPod(0u32)));
224 /// ```
225 #[derive(
226 Debug, Copy, Clone, PartialEq, Eq, Pod, Zeroable, TransparentWrapper,
227 )]
228 #[repr(transparent)]
229 struct NewtypeWrapperTest<T>(T);
230
231 #[test]
fails_cast_contiguous()232 fn fails_cast_contiguous() {
233 let can_cast = CheckedBitPatternEnumWithValues::is_valid_bit_pattern(&5);
234 assert!(!can_cast);
235 }
236
237 #[test]
passes_cast_contiguous()238 fn passes_cast_contiguous() {
239 let res =
240 bytemuck::checked::from_bytes::<CheckedBitPatternEnumWithValues>(&[2u8]);
241 assert_eq!(*res, CheckedBitPatternEnumWithValues::C);
242 }
243
244 #[test]
fails_cast_noncontiguous()245 fn fails_cast_noncontiguous() {
246 let can_cast = CheckedBitPatternEnumNonContiguous::is_valid_bit_pattern(&4);
247 assert!(!can_cast);
248 }
249
250 #[test]
passes_cast_noncontiguous()251 fn passes_cast_noncontiguous() {
252 let res =
253 bytemuck::checked::from_bytes::<CheckedBitPatternEnumNonContiguous>(&[
254 56u8,
255 ]);
256 assert_eq!(*res, CheckedBitPatternEnumNonContiguous::E);
257 }
258
259 #[test]
fails_cast_bytelit()260 fn fails_cast_bytelit() {
261 let can_cast = CheckedBitPatternEnumByteLit::is_valid_bit_pattern(&b'a');
262 assert!(!can_cast);
263 }
264
265 #[test]
passes_cast_bytelit()266 fn passes_cast_bytelit() {
267 let res =
268 bytemuck::checked::cast_slice::<u8, CheckedBitPatternEnumByteLit>(b"CAB");
269 assert_eq!(
270 res,
271 [
272 CheckedBitPatternEnumByteLit::C,
273 CheckedBitPatternEnumByteLit::A,
274 CheckedBitPatternEnumByteLit::B
275 ]
276 );
277 }
278
279 #[test]
fails_cast_struct()280 fn fails_cast_struct() {
281 let pod = [0u8, 24u8];
282 let res = bytemuck::checked::try_from_bytes::<CheckedBitPatternStruct>(&pod);
283 assert!(res.is_err());
284 }
285
286 #[test]
passes_cast_struct()287 fn passes_cast_struct() {
288 let pod = [0u8, 8u8];
289 let res = bytemuck::checked::from_bytes::<CheckedBitPatternStruct>(&pod);
290 assert_eq!(
291 *res,
292 CheckedBitPatternStruct { a: 0, b: CheckedBitPatternEnumNonContiguous::B }
293 );
294 }
295
296 #[test]
anybitpattern_implies_zeroable()297 fn anybitpattern_implies_zeroable() {
298 let test = AnyBitPatternTest::<isize, usize>::zeroed();
299 assert_eq!(test, AnyBitPatternTest { a: 0isize, b: 0usize });
300 }
301
302 #[test]
checkedbitpattern_try_pod_read_unaligned()303 fn checkedbitpattern_try_pod_read_unaligned() {
304 let pod = [0u8];
305 let res = bytemuck::checked::try_pod_read_unaligned::<
306 CheckedBitPatternEnumWithValues,
307 >(&pod);
308 assert!(res.is_ok());
309
310 let pod = [5u8];
311 let res = bytemuck::checked::try_pod_read_unaligned::<
312 CheckedBitPatternEnumWithValues,
313 >(&pod);
314 assert!(res.is_err());
315 }
316
317 #[test]
checkedbitpattern_aligned_struct()318 fn checkedbitpattern_aligned_struct() {
319 let pod = [0u8; 8];
320 bytemuck::checked::pod_read_unaligned::<CheckedBitPatternAlignedStruct>(&pod);
321 }
322
323 #[test]
checkedbitpattern_c_default_discriminant_enum_with_fields()324 fn checkedbitpattern_c_default_discriminant_enum_with_fields() {
325 let pod = [
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0x55,
327 0x55, 0x55, 0x55, 0xcc,
328 ];
329 let value = bytemuck::checked::pod_read_unaligned::<
330 CheckedBitPatternCDefaultDiscriminantEnumWithFields,
331 >(&pod);
332 assert_eq!(
333 value,
334 CheckedBitPatternCDefaultDiscriminantEnumWithFields::A(0xcc555555555555cc)
335 );
336
337 let pod = [
338 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0x55,
339 0x55, 0x55, 0x55, 0xcc,
340 ];
341 let value = bytemuck::checked::pod_read_unaligned::<
342 CheckedBitPatternCDefaultDiscriminantEnumWithFields,
343 >(&pod);
344 assert_eq!(
345 value,
346 CheckedBitPatternCDefaultDiscriminantEnumWithFields::B {
347 c: 0xcc555555555555cc
348 }
349 );
350 }
351
352 #[test]
checkedbitpattern_c_enum_with_fields()353 fn checkedbitpattern_c_enum_with_fields() {
354 let pod = [0x00, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0xcc];
355 let value = bytemuck::checked::pod_read_unaligned::<
356 CheckedBitPatternCEnumWithFields,
357 >(&pod);
358 assert_eq!(value, CheckedBitPatternCEnumWithFields::A(0xcc5555cc));
359
360 let pod = [0x01, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0xcc];
361 let value = bytemuck::checked::pod_read_unaligned::<
362 CheckedBitPatternCEnumWithFields,
363 >(&pod);
364 assert_eq!(value, CheckedBitPatternCEnumWithFields::B { c: 0xcc5555cc });
365 }
366
367 #[test]
checkedbitpattern_int_enum_with_fields()368 fn checkedbitpattern_int_enum_with_fields() {
369 let pod = [0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
370 let value = bytemuck::checked::pod_read_unaligned::<
371 CheckedBitPatternIntEnumWithFields,
372 >(&pod);
373 assert_eq!(value, CheckedBitPatternIntEnumWithFields::A(0x55));
374
375 let pod = [0x01, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0xcc];
376 let value = bytemuck::checked::pod_read_unaligned::<
377 CheckedBitPatternIntEnumWithFields,
378 >(&pod);
379 assert_eq!(value, CheckedBitPatternIntEnumWithFields::B { c: 0xcc5555cc });
380 }
381
382 #[test]
checkedbitpattern_nested_enum_with_fields()383 fn checkedbitpattern_nested_enum_with_fields() {
384 // total size 24 bytes. first byte always the u8 discriminant.
385
386 #[repr(C, align(8))]
387 struct Align8Bytes([u8; 24]);
388
389 // first we'll check variantA, nested variant A
390 let pod = Align8Bytes([
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // byte 0 discriminant = 0 = variant A, bytes 1-7 irrelevant padding.
392 0x00, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0xcc, // bytes 8-15 are the nested CheckedBitPatternCEnumWithFields,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bytes 16-23 padding
394 ]);
395 let value = bytemuck::checked::from_bytes::<
396 CheckedBitPatternEnumNested,
397 >(&pod.0);
398 assert_eq!(value, &CheckedBitPatternEnumNested::A(CheckedBitPatternCEnumWithFields::A(0xcc5555cc)));
399
400 // next we'll check invalid first discriminant fails
401 let pod = Align8Bytes([
402 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // byte 0 discriminant = 2 = invalid, bytes 1-7 padding
403 0x00, 0x00, 0x00, 0x00, 0xcc, 0x55, 0x55, 0xcc, // bytes 8-15 are the nested CheckedBitPatternCEnumWithFields = A,
404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bytes 16-23 padding
405 ]);
406 let result = bytemuck::checked::try_from_bytes::<
407 CheckedBitPatternEnumNested,
408 >(&pod.0);
409 assert_eq!(result, Err(CheckedCastError::InvalidBitPattern));
410
411
412 // next we'll check variant B, nested variant B
413 let pod = Align8Bytes([
414 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // byte 0 discriminant = 1 = variant B, bytes 1-7 padding
415 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bytes 8-15 is C int size discriminant of CheckedBitPatternCDefaultDiscrimimantEnumWithFields, 1 (LE byte order) = variant B
416 0xcc, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xcc, // bytes 16-13 is the data contained in nested variant B
417 ]);
418 let value = bytemuck::checked::from_bytes::<
419 CheckedBitPatternEnumNested,
420 >(&pod.0);
421 assert_eq!(
422 value,
423 &CheckedBitPatternEnumNested::B(CheckedBitPatternCDefaultDiscriminantEnumWithFields::B {
424 c: 0xcc555555555555cc
425 })
426 );
427
428 // finally we'll check variant B, nested invalid discriminant
429 let pod = Align8Bytes([
430 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1 discriminant = variant B, bytes 1-7 padding
431 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bytes 8-15 is C int size discriminant of CheckedBitPatternCDefaultDiscrimimantEnumWithFields, 0x08 is invalid
432 0xcc, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xcc, // bytes 16-13 is the data contained in nested variant B
433 ]);
434 let result = bytemuck::checked::try_from_bytes::<
435 CheckedBitPatternEnumNested,
436 >(&pod.0);
437 assert_eq!(result, Err(CheckedCastError::InvalidBitPattern));
438 }
439 #[test]
checkedbitpattern_transparent_enum_with_fields()440 fn checkedbitpattern_transparent_enum_with_fields() {
441 let pod = [0xcc, 0x55, 0x55, 0xcc];
442 let value = bytemuck::checked::pod_read_unaligned::<
443 CheckedBitPatternTransparentEnumWithFields,
444 >(&pod);
445 assert_eq!(
446 value,
447 CheckedBitPatternTransparentEnumWithFields::A { b: 0xcc5555cc }
448 );
449 }
450
451 #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
452 #[repr(C, align(16))]
453 struct Issue127 {}
454
455 use bytemuck as reexport_name;
456 #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, bytemuck::ByteEq)]
457 #[bytemuck(crate = "reexport_name")]
458 #[repr(C)]
459 struct Issue93 {}
460
461