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