// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // See comment in `include.rs` for why we disable the prelude. #![no_implicit_prelude] #![allow(warnings)] include!("include.rs"); #[derive(Eq, PartialEq, Debug, imp::Immutable, imp::KnownLayout, imp::TryFromBytes)] #[repr(u8)] enum Foo { A, } util_assert_impl_all!(Foo: imp::TryFromBytes); #[test] fn test_foo() { imp::assert_eq!(::try_read_from_bytes(&[0]), imp::Ok(Foo::A)); imp::assert!(::try_read_from_bytes(&[]).is_err()); imp::assert!(::try_read_from_bytes(&[1]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0]).is_err()); } #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)] #[repr(u16)] enum Bar { A = 0, } util_assert_impl_all!(Bar: imp::TryFromBytes); #[test] fn test_bar() { imp::assert_eq!(::try_read_from_bytes(&[0, 0]), imp::Ok(Bar::A)); imp::assert!(::try_read_from_bytes(&[]).is_err()); imp::assert!(::try_read_from_bytes(&[0]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 1]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0, 0]).is_err()); } #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)] #[repr(u32)] enum Baz { A = 1, B = 0, } util_assert_impl_all!(Baz: imp::TryFromBytes); #[test] fn test_baz() { imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&1u32)), imp::Ok(Baz::A) ); imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&0u32)), imp::Ok(Baz::B) ); imp::assert!(::try_read_from_bytes(&[]).is_err()); imp::assert!(::try_read_from_bytes(&[0]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0, 0]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0, 0, 0, 0]).is_err()); } // Test hygiene - make sure that `i8` being shadowed doesn't cause problems for // the code emitted by the derive. type i8 = bool; const THREE: ::core::primitive::i8 = 3; #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)] #[repr(i8)] enum Blah { A = 1, B = 0, C = 1 + 2, D = 3 + THREE, } util_assert_impl_all!(Blah: imp::TryFromBytes); #[test] fn test_blah() { imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&1i8)), imp::Ok(Blah::A) ); imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&0i8)), imp::Ok(Blah::B) ); imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&3i8)), imp::Ok(Blah::C) ); imp::assert_eq!( ::try_read_from_bytes(imp::IntoBytes::as_bytes(&6i8)), imp::Ok(Blah::D) ); imp::assert!(::try_read_from_bytes(&[]).is_err()); imp::assert!(::try_read_from_bytes(&[4]).is_err()); imp::assert!(::try_read_from_bytes(&[0, 0]).is_err()); } #[derive( Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes, )] #[repr(C)] enum FieldlessButNotUnitOnly { A, B(), C {}, } #[test] fn test_fieldless_but_not_unit_only() { const SIZE: usize = ::core::mem::size_of::(); let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::A); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(FieldlessButNotUnitOnly::A) ); let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::B()); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(FieldlessButNotUnitOnly::B()) ); let disc: [u8; SIZE] = ::zerocopy::transmute!(FieldlessButNotUnitOnly::C {}); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(FieldlessButNotUnitOnly::C {}) ); imp::assert!(::try_read_from_bytes( &[0xFF; SIZE][..] ) .is_err()); } #[derive( Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes, )] #[repr(C)] enum WeirdDiscriminants { A = -7, B, C = 33, } #[test] fn test_weird_discriminants() { const SIZE: usize = ::core::mem::size_of::(); let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::A); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(WeirdDiscriminants::A) ); let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::B); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(WeirdDiscriminants::B) ); let disc: [u8; SIZE] = ::zerocopy::transmute!(WeirdDiscriminants::C); imp::assert_eq!( ::try_read_from_bytes(&disc[..]), imp::Ok(WeirdDiscriminants::C) ); imp::assert!( ::try_read_from_bytes(&[0xFF; SIZE][..]).is_err() ); } // Technically non-portable since this is only `IntoBytes` if the discriminant // is an `i32` or `u32`, but we'll cross that bridge when we get to it... #[derive( Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes, )] #[repr(C)] enum HasFields { A(u32), B { foo: ::core::num::NonZeroU32 }, } #[test] fn test_has_fields() { const SIZE: usize = ::core::mem::size_of::(); let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFields::A(10)); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFields::A(10)), ); let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }), ); } #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)] #[repr(C, align(16))] enum HasFieldsAligned { A(u32), B { foo: ::core::num::NonZeroU32 }, } util_assert_impl_all!(HasFieldsAligned: imp::TryFromBytes); #[test] fn test_has_fields_aligned() { const SIZE: usize = ::core::mem::size_of::(); #[derive(imp::IntoBytes)] #[repr(C)] struct BytesOfHasFieldsAligned { has_fields: HasFields, padding: [u8; 8], } let wrap = |has_fields| BytesOfHasFieldsAligned { has_fields, padding: [0; 8] }; let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFields::A(10))); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsAligned::A(10)), ); let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() })); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsAligned::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }), ); } #[derive( Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes, )] #[repr(u32)] enum HasFieldsPrimitive { A(u32), B { foo: ::core::num::NonZeroU32 }, } #[test] fn test_has_fields_primitive() { const SIZE: usize = ::core::mem::size_of::(); let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFieldsPrimitive::A(10)); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsPrimitive::A(10)), ); let bytes: [u8; SIZE] = ::zerocopy::transmute!(HasFieldsPrimitive::B { foo: ::core::num::NonZeroU32::new(123456).unwrap(), }); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsPrimitive::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }), ); } #[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)] #[repr(u32, align(16))] enum HasFieldsPrimitiveAligned { A(u32), B { foo: ::core::num::NonZeroU32 }, } util_assert_impl_all!(HasFieldsPrimitiveAligned: imp::TryFromBytes); #[test] fn test_has_fields_primitive_aligned() { const SIZE: usize = ::core::mem::size_of::(); #[derive(imp::IntoBytes)] #[repr(C)] struct BytesOfHasFieldsPrimitiveAligned { has_fields: HasFieldsPrimitive, padding: [u8; 8], } let wrap = |has_fields| BytesOfHasFieldsPrimitiveAligned { has_fields, padding: [0; 8] }; let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFieldsPrimitive::A(10))); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsPrimitiveAligned::A(10)), ); let bytes: [u8; SIZE] = ::zerocopy::transmute!(wrap(HasFieldsPrimitive::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() })); imp::assert_eq!( ::try_read_from_bytes(&bytes[..]), imp::Ok(HasFieldsPrimitiveAligned::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }), ); } #[derive(imp::TryFromBytes)] #[repr(align(4), u32)] enum HasReprAlignFirst { A, B, } util_assert_impl_all!(HasReprAlignFirst: imp::TryFromBytes); #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)] #[repr(u8)] enum Complex { UnitLike, StructLike { a: u8, b: u16 }, TupleLike(bool, char), } util_assert_impl_all!(Complex: imp::TryFromBytes); #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)] #[repr(u8)] enum ComplexWithGenerics { UnitLike, StructLike { a: u8, b: X }, TupleLike(bool, Y), } util_assert_impl_all!(ComplexWithGenerics: imp::TryFromBytes); #[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)] #[repr(C)] enum GenericWithLifetimes<'a, 'b, X: 'a, Y: 'b> { Foo(::core::marker::PhantomData<&'a X>), Bar(::core::marker::PhantomData<&'b Y>), } #[derive(Clone, Copy, imp::TryFromBytes)] struct A; #[derive(imp::TryFromBytes)] #[repr(C)] enum B { A(A), A2 { a: A }, } #[derive(imp::TryFromBytes)] #[repr(u8)] enum FooU8 { Variant0, Variant1, Variant2, Variant3, Variant4, Variant5, Variant6, Variant7, Variant8, Variant9, Variant10, Variant11, Variant12, Variant13, Variant14, Variant15, Variant16, Variant17, Variant18, Variant19, Variant20, Variant21, Variant22, Variant23, Variant24, Variant25, Variant26, Variant27, Variant28, Variant29, Variant30, Variant31, Variant32, Variant33, Variant34, Variant35, Variant36, Variant37, Variant38, Variant39, Variant40, Variant41, Variant42, Variant43, Variant44, Variant45, Variant46, Variant47, Variant48, Variant49, Variant50, Variant51, Variant52, Variant53, Variant54, Variant55, Variant56, Variant57, Variant58, Variant59, Variant60, Variant61, Variant62, Variant63, Variant64, Variant65, Variant66, Variant67, Variant68, Variant69, Variant70, Variant71, Variant72, Variant73, Variant74, Variant75, Variant76, Variant77, Variant78, Variant79, Variant80, Variant81, Variant82, Variant83, Variant84, Variant85, Variant86, Variant87, Variant88, Variant89, Variant90, Variant91, Variant92, Variant93, Variant94, Variant95, Variant96, Variant97, Variant98, Variant99, Variant100, Variant101, Variant102, Variant103, Variant104, Variant105, Variant106, Variant107, Variant108, Variant109, Variant110, Variant111, Variant112, Variant113, Variant114, Variant115, Variant116, Variant117, Variant118, Variant119, Variant120, Variant121, Variant122, Variant123, Variant124, Variant125, Variant126, Variant127, Variant128, Variant129, Variant130, Variant131, Variant132, Variant133, Variant134, Variant135, Variant136, Variant137, Variant138, Variant139, Variant140, Variant141, Variant142, Variant143, Variant144, Variant145, Variant146, Variant147, Variant148, Variant149, Variant150, Variant151, Variant152, Variant153, Variant154, Variant155, Variant156, Variant157, Variant158, Variant159, Variant160, Variant161, Variant162, Variant163, Variant164, Variant165, Variant166, Variant167, Variant168, Variant169, Variant170, Variant171, Variant172, Variant173, Variant174, Variant175, Variant176, Variant177, Variant178, Variant179, Variant180, Variant181, Variant182, Variant183, Variant184, Variant185, Variant186, Variant187, Variant188, Variant189, Variant190, Variant191, Variant192, Variant193, Variant194, Variant195, Variant196, Variant197, Variant198, Variant199, Variant200, Variant201, Variant202, Variant203, Variant204, Variant205, Variant206, Variant207, Variant208, Variant209, Variant210, Variant211, Variant212, Variant213, Variant214, Variant215, Variant216, Variant217, Variant218, Variant219, Variant220, Variant221, Variant222, Variant223, Variant224, Variant225, Variant226, Variant227, Variant228, Variant229, Variant230, Variant231, Variant232, Variant233, Variant234, Variant235, Variant236, Variant237, Variant238, Variant239, Variant240, Variant241, Variant242, Variant243, Variant244, Variant245, Variant246, Variant247, Variant248, Variant249, Variant250, Variant251, Variant252, Variant253, Variant254, Variant255, } #[test] fn test_trivial_is_bit_valid() { // Though we don't derive `FromBytes`, `FooU8` *could* soundly implement // `FromBytes`. Therefore, `TryFromBytes` derive's `is_bit_valid` impl is // trivial - it unconditionally returns `true`. util_assert_not_impl_any!(FooU8: imp::FromBytes); util::test_trivial_is_bit_valid::(); } #[deny(non_camel_case_types)] mod issue_2051 { use super::*; // Test that the `non_camel_case_types` lint isn't triggered by generated code. // Prevents regressions of #2051. #[repr(u32)] #[derive(imp::TryFromBytes)] #[allow(non_camel_case_types)] pub enum Code { I32_ADD, I32_SUB, I32_MUL, } }