1use core::{cmp::Ordering, ops::Add};
4
5use crate::{
6 RustSpec, Stable, Unstable, Zero,
7 layout::{NonRobust, Robust},
8 mutability::Exclusive,
9 niche::{WithNiche, WithoutNiche},
10 size::{self, MetaSized, SliceLike},
11};
12
13macro_rules! primitive_derive {
14 ( $primitive:ty => $alignment:ty ) => {
15 unsafe impl RustSpec for $primitive {
16 type Layout = Stable;
17 type Size = size::Sized<crate::Gt<Zero>>;
18 type Alignment = $alignment;
19 type Trap = Robust;
20 type Niche = WithoutNiche;
21 type Mutability = Exclusive;
22 type __IndirectTrap = Robust;
23 }
24 };
25}
26
27macro_rules! raw_pointer_derive {
28 ( $mutability:tt ) => {
29 unsafe impl<R: ?Sized> RustSpec for *$mutability R {
30 type Layout = Stable;
31 type Size = size::Sized<crate::Gt<Zero>>;
32 type Alignment = <usize as RustSpec>::Alignment;
33 type Trap = Robust;
34 type Niche = WithoutNiche;
35 type Mutability = Exclusive;
36 type __IndirectTrap = Robust;
37
38 }
39 };
40}
41
42macro_rules! impl_nonempty_array {
43 ($($n:literal),* $(,)?) => { $(
44 unsafe impl<R: RustSpec> RustSpec for [R; $n]
45 where
46 WithoutNiche: Add<R::Niche>,
47 {
48 type Layout = R::Layout;
49 type Size = R::Size;
50 type Alignment = R::Alignment;
51 type Trap = R::Trap;
52 type Niche = <WithoutNiche as Add<R::Niche>>::Output;
53 type Mutability = R::Mutability;
54 type __IndirectTrap = R::__IndirectTrap;
55 })*
56 };
57}
58
59macro_rules! impl_fn_types {
60 ( $( ( $( $arg:ident ),* ) ),* $(,)? ) => {
61 $(
62 impl_fn_types!(@rust fn($($arg),*) -> R; $($arg),*);
63 impl_fn_types!(@rust unsafe fn($($arg),*) -> R; $($arg),*);
64 impl_fn_types!(@abi "C"; $($arg),*);
65 impl_fn_types!(@abi "C-unwind"; $($arg),*);
66 impl_fn_types!(@abi "system"; $($arg),*);
67 impl_fn_types!(@abi "system-unwind"; $($arg),*);
68 #[cfg(target_arch = "x86")]
69 impl_fn_types!(@abi "cdecl"; $($arg),*);
70 #[cfg(target_arch = "x86")]
71 impl_fn_types!(@abi "cdecl-unwind"; $($arg),*);
72 #[cfg(target_arch = "x86")]
73 impl_fn_types!(@abi "stdcall"; $($arg),*);
74 #[cfg(target_arch = "x86")]
75 impl_fn_types!(@abi "stdcall-unwind"; $($arg),*);
76 #[cfg(target_arch = "x86")]
77 impl_fn_types!(@abi "fastcall"; $($arg),*);
78 #[cfg(target_arch = "x86")]
79 impl_fn_types!(@abi "fastcall-unwind"; $($arg),*);
80 #[cfg(target_arch = "x86")]
81 impl_fn_types!(@abi "thiscall"; $($arg),*);
82 #[cfg(target_arch = "x86")]
83 impl_fn_types!(@abi "thiscall-unwind"; $($arg),*);
84 #[cfg(target_arch = "x86_64")]
85 impl_fn_types!(@abi "sysv64"; $($arg),*);
86 #[cfg(target_arch = "x86_64")]
87 impl_fn_types!(@abi "sysv64-unwind"; $($arg),*);
88 #[cfg(target_arch = "x86_64")]
89 impl_fn_types!(@abi "win64"; $($arg),*);
90 #[cfg(target_arch = "x86_64")]
91 impl_fn_types!(@abi "win64-unwind"; $($arg),*);
92 #[cfg(target_arch = "arm")]
93 impl_fn_types!(@abi "aapcs"; $($arg),*);
94 #[cfg(target_arch = "arm")]
95 impl_fn_types!(@abi "aapcs-unwind"; $($arg),*);
96 #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64"))]
97 impl_fn_types!(@abi "efiapi"; $($arg),*);
98 )*
99 };
100 (@abi $abi:literal; $($arg:ident),*) => {
101 impl_fn_types!(@c extern $abi fn($($arg),*) -> R; [] [<R as RustSpec>::Layout]; $($arg),*);
102 impl_fn_types!(@c unsafe extern $abi fn($($arg),*) -> R; [] [<R as RustSpec>::Layout]; $($arg),*);
103 const _: () = {
104 assert!(core::mem::align_of::<extern $abi fn()>() > 1);
105 assert!(core::mem::align_of::<unsafe extern $abi fn()>() > 1);
106 };
107 };
108 (@rust $fn_type:ty; $($arg:ident),*) => {
109 impl_fn_types!(@impl $fn_type; [$($arg,)* R] [Unstable]);
110 };
111 (@c $fn_type:ty; [$($params:tt)*] [$layout:ty]; $next:ident $(, $rest:ident)*) => {
112 impl_fn_types!(@c $fn_type;
113 [$($params)* $next: RustSpec<Layout: Add<$layout>>,]
114 [<<$next as RustSpec>::Layout as Add<$layout>>::Output]; $($rest),*);
115 };
116 (@c $fn_type:ty; [$($params:tt)*] [$layout:ty];) => {
117 impl_fn_types!(@impl $fn_type; [$($params)* R: RustSpec] [$layout]);
118 };
119 (@impl $fn_type:ty; [$($params:tt)*] [$layout:ty]) => {
120 unsafe impl<$($params)*> RustSpec for $fn_type {
121 type Layout = $layout;
122 type Size = size::Sized<crate::Gt<Zero>>;
123 type Alignment = <usize as RustSpec>::Alignment;
124 type Trap = NonRobust;
125 type Niche = WithNiche<Stable>;
126 type Mutability = Exclusive;
127 type __IndirectTrap = Robust;
128 }
129 };
130}
131
132macro_rules! fieldless_enum_derive {
133 ( $src:ty => $alignment:ty ) => {
134 unsafe impl RustSpec for $src {
135 type Layout = Stable;
136 type Size = size::Sized<crate::Gt<Zero>>;
137 type Alignment = $alignment;
138 type Trap = NonRobust;
139 type Niche = WithNiche<Unstable>;
140 type Mutability = Exclusive;
141 type __IndirectTrap = Robust;
142 }
143 };
144}
145
146primitive_derive! { u8 => crate::One }
147primitive_derive! { i8 => crate::One }
148primitive_derive! { u16 => crate::Gt<crate::One> }
149primitive_derive! { i16 => crate::Gt<crate::One> }
150primitive_derive! { u32 => crate::Gt<crate::One> }
151primitive_derive! { i32 => crate::Gt<crate::One> }
152primitive_derive! { u64 => crate::Gt<crate::One> }
153primitive_derive! { i64 => crate::Gt<crate::One> }
154primitive_derive! { u128 => crate::Gt<crate::One> }
155primitive_derive! { i128 => crate::Gt<crate::One> }
156primitive_derive! { f32 => crate::Gt<crate::One> }
157primitive_derive! { f64 => crate::Gt<crate::One> }
158
159#[cfg(target_pointer_width = "16")]
160primitive_derive! { usize => crate::Gt<crate::One> }
161#[cfg(target_pointer_width = "32")]
162primitive_derive! { usize => crate::Gt<crate::One> }
163#[cfg(target_pointer_width = "64")]
164primitive_derive! { usize => crate::Gt<crate::One> }
165
166primitive_derive! { isize => <usize as RustSpec>::Alignment }
167
168raw_pointer_derive! { const }
169raw_pointer_derive! { mut }
170
171unsafe impl<R: RustSpec> RustSpec for [R] {
172 type Layout = R::Layout;
173 type Size = MetaSized<SliceLike>;
174 type Alignment = R::Alignment;
175 type Trap = R::Trap;
176 type Niche = WithoutNiche;
179 type Mutability = R::Mutability;
180 type __IndirectTrap = R::__IndirectTrap;
181}
182
183unsafe impl<R: RustSpec> RustSpec for [R; 0] {
184 type Layout = R::Layout;
185 type Size = size::Sized<Zero>;
186 type Alignment = R::Alignment;
187 type Trap = Robust;
188 type Niche = WithoutNiche;
189 type Mutability = Exclusive;
190 type __IndirectTrap = Robust;
191}
192
193impl_nonempty_array!(
194 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
195 27, 28, 29, 30, 31, 32
196);
197
198impl_fn_types! {
199 (),
200 (A),
201 (A, B),
202 (A, B, C),
203 (A, B, C, D),
204 (A, B, C, D, E),
205 (A, B, C, D, E, F),
206 (A, B, C, D, E, F, G),
207 (A, B, C, D, E, F, G, H),
208 (A, B, C, D, E, F, G, H, I),
209 (A, B, C, D, E, F, G, H, I, J),
210 (A, B, C, D, E, F, G, H, I, J, K),
211 (A, B, C, D, E, F, G, H, I, J, K, L),
212}
213
214const _: () = {
217 assert!(core::mem::align_of::<fn()>() > 1);
218 assert!(core::mem::align_of::<unsafe fn()>() > 1);
219};
220
221fieldless_enum_derive! { char => crate::Gt<crate::One> }
222fieldless_enum_derive! { bool => crate::One }
223fieldless_enum_derive! { Ordering => crate::One }
224
225#[cfg(test)]
226mod tests {
227 #[cfg(feature = "alloc")]
228 use alloc::{boxed::Box, vec::Vec};
229 use static_assertions::assert_impl_all;
230
231 use super::*;
232 use crate::{
233 Unstable,
234 layout::{NonRobust, Robust},
235 niche::WithNiche,
236 };
237
238 #[test]
239 fn function_pointer_classification() {
240 type RustFn = fn();
241 type CFn12 = extern "C" fn(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
242
243 assert_impl_all!(RustFn: RustSpec<Layout = Unstable, Niche = WithNiche<Stable>>);
244 assert_impl_all!(unsafe fn(u8) -> u16: RustSpec<Layout = Unstable>);
245 assert_impl_all!(extern "Rust" fn(u8) -> u16: RustSpec<Layout = Unstable>);
246 assert_impl_all!(extern "C" fn(u8) -> u16: RustSpec<Layout = Stable>);
247 assert_impl_all!(unsafe extern "C" fn(u8) -> u16: RustSpec<Layout = Stable>);
248 assert_impl_all!(extern "C-unwind" fn(u8) -> u16: RustSpec<Layout = Stable>);
249 assert_impl_all!(extern "system" fn(u8) -> u16: RustSpec<Layout = Stable>);
250 assert_impl_all!(extern "system-unwind" fn(u8) -> u16: RustSpec<Layout = Stable>);
251 #[cfg(target_arch = "x86_64")]
252 assert_impl_all!(extern "sysv64" fn(u8) -> u16: RustSpec<Layout = Stable>);
253 #[cfg(target_arch = "x86_64")]
254 assert_impl_all!(extern "win64" fn(u8) -> u16: RustSpec<Layout = Stable>);
255 assert_impl_all!(extern "C" fn((u8,)) -> u16: RustSpec<Layout = Unstable>);
256 assert_impl_all!(extern "C" fn(u8) -> (u16,): RustSpec<Layout = Unstable>);
257 assert_impl_all!(CFn12: RustSpec<Layout = Stable>);
258 }
259
260 #[test]
261 fn function_pointer_option_has_pointer_size() {
262 macro_rules! assert_option_pointer_size {
263 ($pointer:ty) => {
264 assert_eq!(
265 core::mem::size_of::<Option<$pointer>>(),
266 core::mem::size_of::<$pointer>()
267 );
268 };
269 }
270
271 fn named() {}
272 let _: fn() = named;
273
274 assert_option_pointer_size!(fn());
275 assert_option_pointer_size!(unsafe fn(u8) -> u16);
276 assert_option_pointer_size!(extern "C" fn(u8) -> u16);
277 assert_option_pointer_size!(unsafe extern "C-unwind" fn(u8) -> u16);
278 assert_option_pointer_size!(extern "system" fn());
279 }
280
281 #[test]
282 fn robust_u8() {
283 assert_impl_all!(u8:
284 RustSpec<
285 Layout = Stable,
286 Size = size::Sized<crate::Gt<Zero>>,
287 Alignment = crate::One,
288 Trap = Robust,
289 Niche = WithoutNiche,
290 Mutability = Exclusive,
291 __IndirectTrap = Robust,
292 >,
293 );
294 assert_impl_all!(&u8:
295 RustSpec<
296 Layout = Stable,
297 Size = size::Sized<crate::Gt<Zero>>,
298 Alignment = <usize as RustSpec>::Alignment,
299 Trap = NonRobust,
300 Niche = WithNiche<crate::Stable>,
301 Mutability = Exclusive,
302 __IndirectTrap = Robust,
303 >,
304 );
305 assert_impl_all!(&mut u8:
306 RustSpec<
307 Layout = Stable,
308 Size = size::Sized<crate::Gt<Zero>>,
309 Alignment = <usize as RustSpec>::Alignment,
310 Trap = NonRobust,
311 Niche = WithNiche<crate::Stable>,
312 Mutability = Exclusive,
313 __IndirectTrap = Robust,
314 >,
315 );
316 #[cfg(feature = "alloc")]
317 assert_impl_all!(Box<u8>:
318 RustSpec<
319 Layout = Stable,
320 Size = size::Sized<crate::Gt<Zero>>,
321 Alignment = <usize as RustSpec>::Alignment,
322 Trap = NonRobust,
323 Niche = WithNiche<crate::Stable>,
324 Mutability = Exclusive,
325 __IndirectTrap = Robust,
326 >,
327 );
328 assert_impl_all!(&[u8]:
329 RustSpec<
330 Layout = Unstable,
331 Size = size::Sized<crate::Gt<Zero>>,
332 Alignment = <usize as RustSpec>::Alignment,
333 Trap = NonRobust,
334 Niche = WithNiche<crate::Unstable>,
335 Mutability = Exclusive,
336 __IndirectTrap = Robust,
337 >,
338 );
339 assert_impl_all!(&mut [u8]:
340 RustSpec<
341 Layout = Unstable,
342 Size = size::Sized<crate::Gt<Zero>>,
343 Alignment = <usize as RustSpec>::Alignment,
344 Trap = NonRobust,
345 Niche = WithNiche<crate::Unstable>,
346 Mutability = Exclusive,
347 __IndirectTrap = Robust,
348 >,
349 );
350 #[cfg(feature = "alloc")]
351 assert_impl_all!(Box<[u8]>:
352 RustSpec<
353 Layout = Unstable,
354 Size = size::Sized<crate::Gt<Zero>>,
355 Alignment = <usize as RustSpec>::Alignment,
356 Trap = NonRobust,
357 Niche = WithNiche<crate::Unstable>,
358 Mutability = Exclusive,
359 __IndirectTrap = Robust,
360 >,
361 );
362 #[cfg(feature = "alloc")]
363 assert_impl_all!(Vec<u8>:
364 RustSpec<
365 Layout = Unstable,
366 Size = size::Sized<crate::Gt<Zero>>,
367 Alignment = <usize as RustSpec>::Alignment,
368 Trap = NonRobust,
369 Niche = WithNiche<crate::Unstable>,
370 Mutability = Exclusive,
371 __IndirectTrap = Robust,
372 >,
373 );
374 assert_impl_all!([u8; 2]:
375 RustSpec<
376 Layout = Stable,
377 Size = size::Sized<crate::Gt<Zero>>,
378 Alignment = crate::One,
379 Trap = Robust,
380 Niche = WithoutNiche,
381 Mutability = Exclusive,
382 __IndirectTrap = Robust,
383 >,
384 );
385 assert_impl_all!(Option<u8>:
386 RustSpec<
387 Layout = Unstable,
388 Size = size::Sized<crate::Gt<Zero>>,
389 Alignment = crate::One,
390 Trap = NonRobust,
391 Niche = WithNiche<crate::Unstable>,
392 Mutability = Exclusive,
393 __IndirectTrap = Robust,
394 >,
395 );
396 }
397}