1 // Copyright 2023 The Fuchsia Authors
2 //
3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6 // This file may not be copied, modified, or distributed except according to
7 // those terms.
8
9 // See comment in `include.rs` for why we disable the prelude.
10 #![no_implicit_prelude]
11 #![allow(warnings)]
12
13 include!("include.rs");
14
15 #[derive(Eq, PartialEq, Debug, imp::Immutable, imp::KnownLayout, imp::TryFromBytes)]
16 #[repr(u8)]
17 enum Foo {
18 A,
19 }
20
21 util_assert_impl_all!(Foo: imp::TryFromBytes);
22
23 #[test]
test_foo()24 fn test_foo() {
25 imp::assert_eq!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[0]), imp::Ok(Foo::A));
26 imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
27 imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[1]).is_err());
28 imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
29 }
30
31 #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
32 #[repr(u16)]
33 enum Bar {
34 A = 0,
35 }
36
37 util_assert_impl_all!(Bar: imp::TryFromBytes);
38
39 #[test]
test_bar()40 fn test_bar() {
41 imp::assert_eq!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]), imp::Ok(Bar::A));
42 imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
43 imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0]).is_err());
44 imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 1]).is_err());
45 imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0]).is_err());
46 }
47
48 #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
49 #[repr(u32)]
50 enum Baz {
51 A = 1,
52 B = 0,
53 }
54
55 util_assert_impl_all!(Baz: imp::TryFromBytes);
56
57 #[test]
test_baz()58 fn test_baz() {
59 imp::assert_eq!(
60 <Baz as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&1u32)),
61 imp::Ok(Baz::A)
62 );
63 imp::assert_eq!(
64 <Baz as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&0u32)),
65 imp::Ok(Baz::B)
66 );
67 imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
68 imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0]).is_err());
69 imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
70 imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0]).is_err());
71 imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0, 0, 0]).is_err());
72 }
73
74 // Test hygiene - make sure that `i8` being shadowed doesn't cause problems for
75 // the code emitted by the derive.
76 type i8 = bool;
77
78 const THREE: ::core::primitive::i8 = 3;
79
80 #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
81 #[repr(i8)]
82 enum Blah {
83 A = 1,
84 B = 0,
85 C = 1 + 2,
86 D = 3 + THREE,
87 }
88
89 util_assert_impl_all!(Blah: imp::TryFromBytes);
90
91 #[test]
test_blah()92 fn test_blah() {
93 imp::assert_eq!(
94 <Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&1i8)),
95 imp::Ok(Blah::A)
96 );
97 imp::assert_eq!(
98 <Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&0i8)),
99 imp::Ok(Blah::B)
100 );
101 imp::assert_eq!(
102 <Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&3i8)),
103 imp::Ok(Blah::C)
104 );
105 imp::assert_eq!(
106 <Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&6i8)),
107 imp::Ok(Blah::D)
108 );
109 imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
110 imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[4]).is_err());
111 imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
112 }
113
114 #[derive(
115 Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
116 )]
117 #[repr(C)]
118 enum FieldlessButNotUnitOnly {
119 A,
120 B(),
121 C {},
122 }
123
124 #[test]
test_fieldless_but_not_unit_only()125 fn test_fieldless_but_not_unit_only() {
126 const SIZE: usize = ::core::mem::size_of::<FieldlessButNotUnitOnly>();
127 let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::A);
128 imp::assert_eq!(
129 <FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
130 imp::Ok(FieldlessButNotUnitOnly::A)
131 );
132 let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::B());
133 imp::assert_eq!(
134 <FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
135 imp::Ok(FieldlessButNotUnitOnly::B())
136 );
137 let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::C {});
138 imp::assert_eq!(
139 <FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
140 imp::Ok(FieldlessButNotUnitOnly::C {})
141 );
142 imp::assert!(<FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(
143 &[0xFF; SIZE][..]
144 )
145 .is_err());
146 }
147
148 #[derive(
149 Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
150 )]
151 #[repr(C)]
152 enum WeirdDiscriminants {
153 A = -7,
154 B,
155 C = 33,
156 }
157
158 #[test]
test_weird_discriminants()159 fn test_weird_discriminants() {
160 const SIZE: usize = ::core::mem::size_of::<WeirdDiscriminants>();
161 let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::A);
162 imp::assert_eq!(
163 <WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
164 imp::Ok(WeirdDiscriminants::A)
165 );
166 let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::B);
167 imp::assert_eq!(
168 <WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
169 imp::Ok(WeirdDiscriminants::B)
170 );
171 let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::C);
172 imp::assert_eq!(
173 <WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
174 imp::Ok(WeirdDiscriminants::C)
175 );
176 imp::assert!(
177 <WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&[0xFF; SIZE][..]).is_err()
178 );
179 }
180
181 // Technically non-portable since this is only `IntoBytes` if the discriminant
182 // is an `i32` or `u32`, but we'll cross that bridge when we get to it...
183 #[derive(
184 Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
185 )]
186 #[repr(C)]
187 enum HasFields {
188 A(u32),
189 B { foo: ::core::num::NonZeroU32 },
190 }
191
192 #[test]
test_has_fields()193 fn test_has_fields() {
194 const SIZE: usize = ::core::mem::size_of::<HasFields>();
195
196 let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFields::A(10));
197 imp::assert_eq!(
198 <HasFields as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
199 imp::Ok(HasFields::A(10)),
200 );
201
202 let bytes: [u8; SIZE] =
203 ::zerocopy::transmute!(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() });
204 imp::assert_eq!(
205 <HasFields as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
206 imp::Ok(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
207 );
208 }
209
210 #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
211 #[repr(C, align(16))]
212 enum HasFieldsAligned {
213 A(u32),
214 B { foo: ::core::num::NonZeroU32 },
215 }
216
217 util_assert_impl_all!(HasFieldsAligned: imp::TryFromBytes);
218
219 #[test]
test_has_fields_aligned()220 fn test_has_fields_aligned() {
221 const SIZE: usize = ::core::mem::size_of::<HasFieldsAligned>();
222
223 #[derive(imp::IntoBytes)]
224 #[repr(C)]
225 struct BytesOfHasFieldsAligned {
226 has_fields: HasFields,
227 padding: [u8; 8],
228 }
229
230 let wrap = |has_fields| BytesOfHasFieldsAligned { has_fields, padding: [0; 8] };
231
232 let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFields::A(10)));
233 imp::assert_eq!(
234 <HasFieldsAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
235 imp::Ok(HasFieldsAligned::A(10)),
236 );
237
238 let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFields::B {
239 foo: ::core::num::NonZeroU32::new(123456).unwrap()
240 }));
241 imp::assert_eq!(
242 <HasFieldsAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
243 imp::Ok(HasFieldsAligned::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
244 );
245 }
246
247 #[derive(
248 Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
249 )]
250 #[repr(u32)]
251 enum HasFieldsPrimitive {
252 A(u32),
253 B { foo: ::core::num::NonZeroU32 },
254 }
255
256 #[test]
test_has_fields_primitive()257 fn test_has_fields_primitive() {
258 const SIZE: usize = ::core::mem::size_of::<HasFieldsPrimitive>();
259
260 let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFieldsPrimitive::A(10));
261 imp::assert_eq!(
262 <HasFieldsPrimitive as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
263 imp::Ok(HasFieldsPrimitive::A(10)),
264 );
265
266 let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFieldsPrimitive::B {
267 foo: ::core::num::NonZeroU32::new(123456).unwrap(),
268 });
269 imp::assert_eq!(
270 <HasFieldsPrimitive as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
271 imp::Ok(HasFieldsPrimitive::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
272 );
273 }
274
275 #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
276 #[repr(u32, align(16))]
277 enum HasFieldsPrimitiveAligned {
278 A(u32),
279 B { foo: ::core::num::NonZeroU32 },
280 }
281
282 util_assert_impl_all!(HasFieldsPrimitiveAligned: imp::TryFromBytes);
283
284 #[test]
test_has_fields_primitive_aligned()285 fn test_has_fields_primitive_aligned() {
286 const SIZE: usize = ::core::mem::size_of::<HasFieldsPrimitiveAligned>();
287
288 #[derive(imp::IntoBytes)]
289 #[repr(C)]
290 struct BytesOfHasFieldsPrimitiveAligned {
291 has_fields: HasFieldsPrimitive,
292 padding: [u8; 8],
293 }
294
295 let wrap = |has_fields| BytesOfHasFieldsPrimitiveAligned { has_fields, padding: [0; 8] };
296
297 let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFieldsPrimitive::A(10)));
298 imp::assert_eq!(
299 <HasFieldsPrimitiveAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
300 imp::Ok(HasFieldsPrimitiveAligned::A(10)),
301 );
302
303 let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFieldsPrimitive::B {
304 foo: ::core::num::NonZeroU32::new(123456).unwrap()
305 }));
306 imp::assert_eq!(
307 <HasFieldsPrimitiveAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
308 imp::Ok(HasFieldsPrimitiveAligned::B {
309 foo: ::core::num::NonZeroU32::new(123456).unwrap()
310 }),
311 );
312 }
313
314 #[derive(imp::TryFromBytes)]
315 #[repr(align(4), u32)]
316 enum HasReprAlignFirst {
317 A,
318 B,
319 }
320
321 util_assert_impl_all!(HasReprAlignFirst: imp::TryFromBytes);
322
323 #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
324 #[repr(u8)]
325 enum Complex {
326 UnitLike,
327 StructLike { a: u8, b: u16 },
328 TupleLike(bool, char),
329 }
330
331 util_assert_impl_all!(Complex: imp::TryFromBytes);
332
333 #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
334 #[repr(u8)]
335 enum ComplexWithGenerics<X, Y> {
336 UnitLike,
337 StructLike { a: u8, b: X },
338 TupleLike(bool, Y),
339 }
340
341 util_assert_impl_all!(ComplexWithGenerics<u16, char>: imp::TryFromBytes);
342
343 #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
344 #[repr(C)]
345 enum GenericWithLifetimes<'a, 'b, X: 'a, Y: 'b> {
346 Foo(::core::marker::PhantomData<&'a X>),
347 Bar(::core::marker::PhantomData<&'b Y>),
348 }
349
350 #[derive(Clone, Copy, imp::TryFromBytes)]
351 struct A;
352
353 #[derive(imp::TryFromBytes)]
354 #[repr(C)]
355 enum B {
356 A(A),
357 A2 { a: A },
358 }
359
360 #[derive(imp::TryFromBytes)]
361 #[repr(u8)]
362 enum FooU8 {
363 Variant0,
364 Variant1,
365 Variant2,
366 Variant3,
367 Variant4,
368 Variant5,
369 Variant6,
370 Variant7,
371 Variant8,
372 Variant9,
373 Variant10,
374 Variant11,
375 Variant12,
376 Variant13,
377 Variant14,
378 Variant15,
379 Variant16,
380 Variant17,
381 Variant18,
382 Variant19,
383 Variant20,
384 Variant21,
385 Variant22,
386 Variant23,
387 Variant24,
388 Variant25,
389 Variant26,
390 Variant27,
391 Variant28,
392 Variant29,
393 Variant30,
394 Variant31,
395 Variant32,
396 Variant33,
397 Variant34,
398 Variant35,
399 Variant36,
400 Variant37,
401 Variant38,
402 Variant39,
403 Variant40,
404 Variant41,
405 Variant42,
406 Variant43,
407 Variant44,
408 Variant45,
409 Variant46,
410 Variant47,
411 Variant48,
412 Variant49,
413 Variant50,
414 Variant51,
415 Variant52,
416 Variant53,
417 Variant54,
418 Variant55,
419 Variant56,
420 Variant57,
421 Variant58,
422 Variant59,
423 Variant60,
424 Variant61,
425 Variant62,
426 Variant63,
427 Variant64,
428 Variant65,
429 Variant66,
430 Variant67,
431 Variant68,
432 Variant69,
433 Variant70,
434 Variant71,
435 Variant72,
436 Variant73,
437 Variant74,
438 Variant75,
439 Variant76,
440 Variant77,
441 Variant78,
442 Variant79,
443 Variant80,
444 Variant81,
445 Variant82,
446 Variant83,
447 Variant84,
448 Variant85,
449 Variant86,
450 Variant87,
451 Variant88,
452 Variant89,
453 Variant90,
454 Variant91,
455 Variant92,
456 Variant93,
457 Variant94,
458 Variant95,
459 Variant96,
460 Variant97,
461 Variant98,
462 Variant99,
463 Variant100,
464 Variant101,
465 Variant102,
466 Variant103,
467 Variant104,
468 Variant105,
469 Variant106,
470 Variant107,
471 Variant108,
472 Variant109,
473 Variant110,
474 Variant111,
475 Variant112,
476 Variant113,
477 Variant114,
478 Variant115,
479 Variant116,
480 Variant117,
481 Variant118,
482 Variant119,
483 Variant120,
484 Variant121,
485 Variant122,
486 Variant123,
487 Variant124,
488 Variant125,
489 Variant126,
490 Variant127,
491 Variant128,
492 Variant129,
493 Variant130,
494 Variant131,
495 Variant132,
496 Variant133,
497 Variant134,
498 Variant135,
499 Variant136,
500 Variant137,
501 Variant138,
502 Variant139,
503 Variant140,
504 Variant141,
505 Variant142,
506 Variant143,
507 Variant144,
508 Variant145,
509 Variant146,
510 Variant147,
511 Variant148,
512 Variant149,
513 Variant150,
514 Variant151,
515 Variant152,
516 Variant153,
517 Variant154,
518 Variant155,
519 Variant156,
520 Variant157,
521 Variant158,
522 Variant159,
523 Variant160,
524 Variant161,
525 Variant162,
526 Variant163,
527 Variant164,
528 Variant165,
529 Variant166,
530 Variant167,
531 Variant168,
532 Variant169,
533 Variant170,
534 Variant171,
535 Variant172,
536 Variant173,
537 Variant174,
538 Variant175,
539 Variant176,
540 Variant177,
541 Variant178,
542 Variant179,
543 Variant180,
544 Variant181,
545 Variant182,
546 Variant183,
547 Variant184,
548 Variant185,
549 Variant186,
550 Variant187,
551 Variant188,
552 Variant189,
553 Variant190,
554 Variant191,
555 Variant192,
556 Variant193,
557 Variant194,
558 Variant195,
559 Variant196,
560 Variant197,
561 Variant198,
562 Variant199,
563 Variant200,
564 Variant201,
565 Variant202,
566 Variant203,
567 Variant204,
568 Variant205,
569 Variant206,
570 Variant207,
571 Variant208,
572 Variant209,
573 Variant210,
574 Variant211,
575 Variant212,
576 Variant213,
577 Variant214,
578 Variant215,
579 Variant216,
580 Variant217,
581 Variant218,
582 Variant219,
583 Variant220,
584 Variant221,
585 Variant222,
586 Variant223,
587 Variant224,
588 Variant225,
589 Variant226,
590 Variant227,
591 Variant228,
592 Variant229,
593 Variant230,
594 Variant231,
595 Variant232,
596 Variant233,
597 Variant234,
598 Variant235,
599 Variant236,
600 Variant237,
601 Variant238,
602 Variant239,
603 Variant240,
604 Variant241,
605 Variant242,
606 Variant243,
607 Variant244,
608 Variant245,
609 Variant246,
610 Variant247,
611 Variant248,
612 Variant249,
613 Variant250,
614 Variant251,
615 Variant252,
616 Variant253,
617 Variant254,
618 Variant255,
619 }
620
621 #[test]
test_trivial_is_bit_valid()622 fn test_trivial_is_bit_valid() {
623 // Though we don't derive `FromBytes`, `FooU8` *could* soundly implement
624 // `FromBytes`. Therefore, `TryFromBytes` derive's `is_bit_valid` impl is
625 // trivial - it unconditionally returns `true`.
626 util_assert_not_impl_any!(FooU8: imp::FromBytes);
627 util::test_trivial_is_bit_valid::<FooU8>();
628 }
629
630 #[deny(non_camel_case_types)]
631 mod issue_2051 {
632 use super::*;
633
634 // Test that the `non_camel_case_types` lint isn't triggered by generated code.
635 // Prevents regressions of #2051.
636 #[repr(u32)]
637 #[derive(imp::TryFromBytes)]
638 #[allow(non_camel_case_types)]
639 pub enum Code {
640 I32_ADD,
641 I32_SUB,
642 I32_MUL,
643 }
644 }
645