Skip to main content

rust_spec/
primitives.rs

1//! Logic related to the conversion of primitives to and from FFI-compatible representation
2
3use 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    // TODO: This should not be set at all
177    // however we set it to help some impls
178    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
214// The alignment marker is Gt<One> on the supported targets. Check only that
215// category; function and data pointers need not have identical alignment.
216const _: () = {
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}