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 // 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 // A struct is `IntoBytes` if: 16 // - all fields are `IntoBytes` 17 // - `repr(C)` or `repr(transparent)` and 18 // - no padding (size of struct equals sum of size of field types) 19 // - `repr(packed)` 20 21 #[derive(imp::IntoBytes)] 22 #[repr(C)] 23 struct CZst; 24 25 util_assert_impl_all!(CZst: imp::IntoBytes); 26 27 #[derive(imp::IntoBytes)] 28 #[repr(C)] 29 struct C { 30 a: u8, 31 b: u8, 32 c: util::AU16, 33 } 34 35 util_assert_impl_all!(C: imp::IntoBytes); 36 37 #[derive(imp::IntoBytes)] 38 #[repr(transparent)] 39 struct Transparent { 40 a: u8, 41 b: CZst, 42 } 43 44 util_assert_impl_all!(Transparent: imp::IntoBytes); 45 46 #[derive(imp::IntoBytes)] 47 #[repr(transparent)] 48 struct TransparentGeneric<T: ?imp::Sized> { 49 a: CZst, 50 b: T, 51 } 52 53 util_assert_impl_all!(TransparentGeneric<u64>: imp::IntoBytes); 54 util_assert_impl_all!(TransparentGeneric<[u64]>: imp::IntoBytes); 55 56 #[derive(imp::IntoBytes)] 57 #[repr(C, packed)] 58 struct CZstPacked; 59 60 util_assert_impl_all!(CZstPacked: imp::IntoBytes); 61 62 #[derive(imp::IntoBytes)] 63 #[repr(C, packed)] 64 struct CPacked { 65 a: u8, 66 // NOTE: The `u16` type is not guaranteed to have alignment 2, although it 67 // does on many platforms. However, to fix this would require a custom type 68 // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not 69 // allowed to transitively contain `#[repr(align(...))]` types. Thus, we 70 // have no choice but to use `u16` here. Luckily, these tests run in CI on 71 // platforms on which `u16` has alignment 2, so this isn't that big of a 72 // deal. 73 b: u16, 74 } 75 76 util_assert_impl_all!(CPacked: imp::IntoBytes); 77 78 #[derive(imp::IntoBytes)] 79 #[repr(C, packed(2))] 80 // The same caveats as for CPacked apply - we're assuming u64 is at least 81 // 4-byte aligned by default. Without packed(2), this should fail, as there 82 // would be padding between a/b assuming u64 is 4+ byte aligned. 83 struct CPacked2 { 84 a: u16, 85 b: u64, 86 } 87 88 util_assert_impl_all!(CPacked2: imp::IntoBytes); 89 90 #[derive(imp::IntoBytes)] 91 #[repr(C, packed)] 92 struct CPackedGeneric<T, U: ?imp::Sized> { 93 t: T, 94 // Unsized types stored in `repr(packed)` structs must not be dropped 95 // because dropping them in-place might be unsound depending on the 96 // alignment of the outer struct. Sized types can be dropped by first being 97 // moved to an aligned stack variable, but this isn't possible with unsized 98 // types. 99 u: imp::ManuallyDrop<U>, 100 } 101 102 util_assert_impl_all!(CPackedGeneric<u8, util::AU16>: imp::IntoBytes); 103 util_assert_impl_all!(CPackedGeneric<u8, [util::AU16]>: imp::IntoBytes); 104 105 #[derive(imp::IntoBytes)] 106 #[repr(packed)] 107 struct PackedGeneric<T, U: ?imp::Sized> { 108 t: T, 109 // Unsized types stored in `repr(packed)` structs must not be dropped 110 // because dropping them in-place might be unsound depending on the 111 // alignment of the outer struct. Sized types can be dropped by first being 112 // moved to an aligned stack variable, but this isn't possible with unsized 113 // types. 114 u: imp::ManuallyDrop<U>, 115 } 116 117 util_assert_impl_all!(PackedGeneric<u8, util::AU16>: imp::IntoBytes); 118 util_assert_impl_all!(PackedGeneric<u8, [util::AU16]>: imp::IntoBytes); 119 120 // This test is non-portable, but works so long as Rust happens to lay this 121 // struct out with no padding. 122 #[derive(imp::IntoBytes)] 123 struct Unpacked { 124 a: u8, 125 b: u8, 126 } 127 128 util_assert_impl_all!(Unpacked: imp::IntoBytes); 129 130 #[derive(imp::IntoBytes)] 131 #[repr(C)] 132 struct ReprCGenericOneField<T: ?imp::Sized> { 133 t: T, 134 } 135 136 // Even though `ReprCGenericOneField` has generic type arguments, since it only 137 // has one field, we don't require that its field types implement `Unaligned`. 138 util_assert_impl_all!(ReprCGenericOneField<util::AU16>: imp::IntoBytes); 139 util_assert_impl_all!(ReprCGenericOneField<[util::AU16]>: imp::IntoBytes); 140 141 #[derive(imp::IntoBytes)] 142 #[repr(C)] 143 struct ReprCGenericMultipleFields<T, U: ?imp::Sized> { 144 t: T, 145 u: U, 146 } 147 148 // Since `ReprCGenericMultipleFields` is generic and has more than one field, 149 // all field types must implement `Unaligned`. 150 util_assert_impl_all!(ReprCGenericMultipleFields<u8, [u8; 2]>: imp::IntoBytes); 151 util_assert_impl_all!(ReprCGenericMultipleFields<u8, [[u8; 2]]>: imp::IntoBytes); 152 util_assert_not_impl_any!(ReprCGenericMultipleFields<u8, util::AU16>: imp::IntoBytes); 153 util_assert_not_impl_any!(ReprCGenericMultipleFields<u8, [util::AU16]>: imp::IntoBytes); 154 155 #[derive(imp::IntoBytes)] 156 #[repr(transparent)] 157 struct Unsized { 158 a: [u8], 159 } 160 161 util_assert_impl_all!(Unsized: imp::IntoBytes); 162 163 // Deriving `IntoBytes` should work if the struct has bounded parameters. 164 165 #[derive(imp::IntoBytes)] 166 #[repr(transparent)] 167 struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::IntoBytes, const N: usize>( 168 [T; N], 169 imp::PhantomData<&'a &'b ()>, 170 ) 171 where 172 'a: 'b, 173 'b: 'a, 174 T: 'a + 'b + imp::IntoBytes; 175 176 util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::IntoBytes); 177 178 // Test for the failure reported in #1182. 179 180 #[derive(imp::IntoBytes)] 181 #[repr(C, packed)] 182 pub struct IndexEntryFlags(u8); 183 184 #[derive(imp::IntoBytes)] 185 #[repr(C, packed)] 186 pub struct IndexEntry<const SIZE_BLOCK_ID: usize> { 187 block_number: imp::native_endian::U64, 188 flags: IndexEntryFlags, 189 block_id: [u8; SIZE_BLOCK_ID], 190 } 191 192 util_assert_impl_all!(IndexEntry<0>: imp::IntoBytes); 193 util_assert_impl_all!(IndexEntry<1>: imp::IntoBytes); 194