• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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