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    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    // TODO: This should not be set at all
187    // however we set it to help some impls
188    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
226// The alignment marker is Gt<One> on the supported targets. Check only that
227// category; function and data pointers need not have identical alignment.
228const _: () = {
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}