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