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