diff options
Diffstat (limited to 'tests/struct_as_bytes.rs')
-rw-r--r-- | tests/struct_as_bytes.rs | 98 |
1 files changed, 81 insertions, 17 deletions
diff --git a/tests/struct_as_bytes.rs b/tests/struct_as_bytes.rs index fd464ce..e1507aa 100644 --- a/tests/struct_as_bytes.rs +++ b/tests/struct_as_bytes.rs @@ -4,20 +4,13 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +mod util; -use zerocopy::AsBytes; +use std::{marker::PhantomData, mem::ManuallyDrop, option::IntoIter}; -struct IsAsBytes<T: AsBytes>(T); +use {static_assertions::assert_impl_all, zerocopy::AsBytes}; -// Fail compilation if `$ty: !AsBytes`. -macro_rules! is_as_bytes { - ($ty:ty) => { - const _: () = { - let _: IsAsBytes<$ty>; - }; - }; -} +use self::util::AU16; // A struct is `AsBytes` if: // - all fields are `AsBytes` @@ -29,17 +22,17 @@ macro_rules! is_as_bytes { #[repr(C)] struct CZst; -is_as_bytes!(CZst); +assert_impl_all!(CZst: AsBytes); #[derive(AsBytes)] #[repr(C)] struct C { a: u8, b: u8, - c: u16, + c: AU16, } -is_as_bytes!(C); +assert_impl_all!(C: AsBytes); #[derive(AsBytes)] #[repr(transparent)] @@ -48,19 +41,90 @@ struct Transparent { b: CZst, } -is_as_bytes!(Transparent); +assert_impl_all!(Transparent: AsBytes); + +#[derive(AsBytes)] +#[repr(transparent)] +struct TransparentGeneric<T: ?Sized> { + a: CZst, + b: T, +} + +assert_impl_all!(TransparentGeneric<u64>: AsBytes); +assert_impl_all!(TransparentGeneric<[u64]>: AsBytes); #[derive(AsBytes)] #[repr(C, packed)] struct CZstPacked; -is_as_bytes!(CZstPacked); +assert_impl_all!(CZstPacked: AsBytes); #[derive(AsBytes)] #[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, +} + +assert_impl_all!(CPacked: AsBytes); + +#[derive(AsBytes)] +#[repr(C, packed)] +struct CPackedGeneric<T, U: ?Sized> { + 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: ManuallyDrop<U>, +} + +assert_impl_all!(CPackedGeneric<u8, AU16>: AsBytes); +assert_impl_all!(CPackedGeneric<u8, [AU16]>: AsBytes); + +#[derive(AsBytes)] +#[repr(packed)] +struct Packed { + 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, } -is_as_bytes!(CPacked); +assert_impl_all!(Packed: AsBytes); + +#[derive(AsBytes)] +#[repr(packed)] +struct PackedGeneric<T, U: ?Sized> { + 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: ManuallyDrop<U>, +} + +assert_impl_all!(PackedGeneric<u8, AU16>: AsBytes); +assert_impl_all!(PackedGeneric<u8, [AU16]>: AsBytes); + +#[derive(AsBytes)] +#[repr(transparent)] +struct Unsized { + a: [u8], +} + +assert_impl_all!(Unsized: AsBytes); |