1 // Copyright 2019 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 #![allow(warnings)] 10 11 mod util; 12 13 use std::{marker::PhantomData, mem::ManuallyDrop, option::IntoIter}; 14 15 use {static_assertions::assert_impl_all, zerocopy::AsBytes}; 16 17 use self::util::AU16; 18 19 // A struct is `AsBytes` if: 20 // - all fields are `AsBytes` 21 // - `repr(C)` or `repr(transparent)` and 22 // - no padding (size of struct equals sum of size of field types) 23 // - `repr(packed)` 24 25 #[derive(AsBytes)] 26 #[repr(C)] 27 struct CZst; 28 29 assert_impl_all!(CZst: AsBytes); 30 31 #[derive(AsBytes)] 32 #[repr(C)] 33 struct C { 34 a: u8, 35 b: u8, 36 c: AU16, 37 } 38 39 assert_impl_all!(C: AsBytes); 40 41 #[derive(AsBytes)] 42 #[repr(transparent)] 43 struct Transparent { 44 a: u8, 45 b: CZst, 46 } 47 48 assert_impl_all!(Transparent: AsBytes); 49 50 #[derive(AsBytes)] 51 #[repr(transparent)] 52 struct TransparentGeneric<T: ?Sized> { 53 a: CZst, 54 b: T, 55 } 56 57 assert_impl_all!(TransparentGeneric<u64>: AsBytes); 58 assert_impl_all!(TransparentGeneric<[u64]>: AsBytes); 59 60 #[derive(AsBytes)] 61 #[repr(C, packed)] 62 struct CZstPacked; 63 64 assert_impl_all!(CZstPacked: AsBytes); 65 66 #[derive(AsBytes)] 67 #[repr(C, packed)] 68 struct CPacked { 69 a: u8, 70 // NOTE: The `u16` type is not guaranteed to have alignment 2, although it 71 // does on many platforms. However, to fix this would require a custom type 72 // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not 73 // allowed to transitively contain `#[repr(align(...))]` types. Thus, we 74 // have no choice but to use `u16` here. Luckily, these tests run in CI on 75 // platforms on which `u16` has alignment 2, so this isn't that big of a 76 // deal. 77 b: u16, 78 } 79 80 assert_impl_all!(CPacked: AsBytes); 81 82 #[derive(AsBytes)] 83 #[repr(C, packed(2))] 84 // The same caveats as for CPacked apply - we're assuming u64 is at least 85 // 4-byte aligned by default. Without packed(2), this should fail, as there 86 // would be padding between a/b assuming u64 is 4+ byte aligned. 87 struct CPacked2 { 88 a: u16, 89 b: u64, 90 } 91 92 assert_impl_all!(CPacked2: AsBytes); 93 94 #[derive(AsBytes)] 95 #[repr(C, packed)] 96 struct CPackedGeneric<T, U: ?Sized> { 97 t: T, 98 // Unsized types stored in `repr(packed)` structs must not be dropped 99 // because dropping them in-place might be unsound depending on the 100 // alignment of the outer struct. Sized types can be dropped by first being 101 // moved to an aligned stack variable, but this isn't possible with unsized 102 // types. 103 u: ManuallyDrop<U>, 104 } 105 106 assert_impl_all!(CPackedGeneric<u8, AU16>: AsBytes); 107 assert_impl_all!(CPackedGeneric<u8, [AU16]>: AsBytes); 108 109 #[derive(AsBytes)] 110 #[repr(packed)] 111 struct Packed { 112 a: u8, 113 // NOTE: The `u16` type is not guaranteed to have alignment 2, although it 114 // does on many platforms. However, to fix this would require a custom type 115 // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not 116 // allowed to transitively contain `#[repr(align(...))]` types. Thus, we 117 // have no choice but to use `u16` here. Luckily, these tests run in CI on 118 // platforms on which `u16` has alignment 2, so this isn't that big of a 119 // deal. 120 b: u16, 121 } 122 123 assert_impl_all!(Packed: AsBytes); 124 125 #[derive(AsBytes)] 126 #[repr(packed)] 127 struct PackedGeneric<T, U: ?Sized> { 128 t: T, 129 // Unsized types stored in `repr(packed)` structs must not be dropped 130 // because dropping them in-place might be unsound depending on the 131 // alignment of the outer struct. Sized types can be dropped by first being 132 // moved to an aligned stack variable, but this isn't possible with unsized 133 // types. 134 u: ManuallyDrop<U>, 135 } 136 137 assert_impl_all!(PackedGeneric<u8, AU16>: AsBytes); 138 assert_impl_all!(PackedGeneric<u8, [AU16]>: AsBytes); 139 140 #[derive(AsBytes)] 141 #[repr(transparent)] 142 struct Unsized { 143 a: [u8], 144 } 145 146 assert_impl_all!(Unsized: AsBytes); 147 148 // Deriving `AsBytes` should work if the struct has bounded parameters. 149 150 #[derive(AsBytes)] 151 #[repr(transparent)] 152 struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + AsBytes>( 153 [T; N], 154 PhantomData<&'a &'b ()>, 155 ) 156 where 157 'a: 'b, 158 'b: 'a, 159 T: 'a + 'b + AsBytes; 160 161 assert_impl_all!(WithParams<'static, 'static, 42, u8>: AsBytes); 162