// Copyright 2019 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"); // A struct is `IntoBytes` if: // - all fields are `IntoBytes` // - `repr(C)` or `repr(transparent)` and // - no padding (size of struct equals sum of size of field types) // - `repr(packed)` #[derive(imp::IntoBytes)] #[repr(C)] struct CZst; util_assert_impl_all!(CZst: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C)] struct C { a: u8, b: u8, c: util::AU16, } util_assert_impl_all!(C: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C)] struct SyntacticUnsized { a: u8, b: u8, c: [util::AU16], } util_assert_impl_all!(C: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(transparent)] struct Transparent { a: u8, b: CZst, } util_assert_impl_all!(Transparent: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(transparent)] struct TransparentGeneric { a: CZst, b: T, } util_assert_impl_all!(TransparentGeneric: imp::IntoBytes); util_assert_impl_all!(TransparentGeneric<[u64]>: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C, packed)] struct CZstPacked; util_assert_impl_all!(CZstPacked: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C, packed)] struct CPacked { a: u8, // NOTE: The `u16` type is not guaranteed to have alignment 2, although it // does on many platforms. However, to fix this would require a custom type // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not // allowed to transitively contain `#[repr(align(...))]` types. Thus, we // have no choice but to use `u16` here. Luckily, these tests run in CI on // platforms on which `u16` has alignment 2, so this isn't that big of a // deal. b: u16, } util_assert_impl_all!(CPacked: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C, packed(2))] // The same caveats as for CPacked apply - we're assuming u64 is at least // 4-byte aligned by default. Without packed(2), this should fail, as there // would be padding between a/b assuming u64 is 4+ byte aligned. struct CPacked2 { a: u16, b: u64, } util_assert_impl_all!(CPacked2: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C, packed)] struct CPackedGeneric { t: T, // Unsized types stored in `repr(packed)` structs must not be dropped // because dropping them in-place might be unsound depending on the // alignment of the outer struct. Sized types can be dropped by first being // moved to an aligned stack variable, but this isn't possible with unsized // types. u: imp::ManuallyDrop, } util_assert_impl_all!(CPackedGeneric: imp::IntoBytes); util_assert_impl_all!(CPackedGeneric: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(packed)] struct PackedGeneric { t: T, // Unsized types stored in `repr(packed)` structs must not be dropped // because dropping them in-place might be unsound depending on the // alignment of the outer struct. Sized types can be dropped by first being // moved to an aligned stack variable, but this isn't possible with unsized // types. u: imp::ManuallyDrop, } util_assert_impl_all!(PackedGeneric: imp::IntoBytes); util_assert_impl_all!(PackedGeneric: imp::IntoBytes); // This test is non-portable, but works so long as Rust happens to lay this // struct out with no padding. #[derive(imp::IntoBytes)] struct Unpacked { a: u8, b: u8, } util_assert_impl_all!(Unpacked: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C)] struct ReprCGenericOneField { t: T, } // Even though `ReprCGenericOneField` has generic type arguments, since it only // has one field, we don't require that its field types implement `Unaligned`. util_assert_impl_all!(ReprCGenericOneField: imp::IntoBytes); util_assert_impl_all!(ReprCGenericOneField<[util::AU16]>: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(C)] struct ReprCGenericMultipleFields { t: T, u: U, } // Since `ReprCGenericMultipleFields` is generic and has more than one field, // all field types must implement `Unaligned`. util_assert_impl_all!(ReprCGenericMultipleFields: imp::IntoBytes); util_assert_impl_all!(ReprCGenericMultipleFields: imp::IntoBytes); util_assert_not_impl_any!(ReprCGenericMultipleFields: imp::IntoBytes); util_assert_not_impl_any!(ReprCGenericMultipleFields: imp::IntoBytes); #[derive(imp::IntoBytes)] #[repr(transparent)] struct Unsized { a: [u8], } util_assert_impl_all!(Unsized: imp::IntoBytes); // Deriving `IntoBytes` should work if the struct has bounded parameters. #[derive(imp::IntoBytes)] #[repr(transparent)] struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::IntoBytes, const N: usize>( [T; N], imp::PhantomData<&'a &'b ()>, ) where 'a: 'b, 'b: 'a, T: 'a + 'b + imp::IntoBytes; util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::IntoBytes); // Test for the failure reported in #1182. #[derive(imp::IntoBytes)] #[repr(C, packed)] pub struct IndexEntryFlags(u8); #[derive(imp::IntoBytes)] #[repr(C, packed)] pub struct IndexEntry { block_number: imp::native_endian::U64, flags: IndexEntryFlags, block_id: [u8; SIZE_BLOCK_ID], } util_assert_impl_all!(IndexEntry<0>: imp::IntoBytes); util_assert_impl_all!(IndexEntry<1>: imp::IntoBytes);