fn_ptr/
impl.rs

1// NOTE: ABI target cfgs are provided by the build script as `has_abi_<name>`.
2
3macro_rules! cfg_all {
4    ($meta:meta { $($items:item)* }) => {
5        $(#[cfg($meta)] $items)*
6    };
7}
8
9macro_rules! impl_fn {
10    (@recurse () ($($nm:ident : $ty:ident),*)) => {
11        impl_fn!(@impl_all ($($nm : $ty),*));
12    };
13    (@recurse ($hd_nm:ident : $hd_ty:ident $(, $tl_nm:ident : $tl_ty:ident)*) ($($nm:ident : $ty:ident),*)) => {
14        impl_fn!(@impl_all ($($nm : $ty),*));
15        impl_fn!(@recurse ($($tl_nm : $tl_ty),*) ($($nm : $ty,)* $hd_nm : $hd_ty));
16    };
17
18    (@impl_all ($($nm:ident : $ty:ident),*)) => {
19        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Rust, "Rust");
20        impl_fn!(@impl_u_and_s ($($nm : $ty),*), C, "C");
21        impl_fn!(@impl_u_and_s ($($nm : $ty),*), System, "system");
22        #[cfg(has_abi_cdecl)]
23        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Cdecl, "cdecl");
24        #[cfg(has_abi_stdcall)]
25        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Stdcall, "stdcall");
26        #[cfg(has_abi_fastcall)]
27        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Fastcall, "fastcall");
28        #[cfg(has_abi_win64)]
29        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Win64, "win64");
30        #[cfg(has_abi_sysv64)]
31        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Sysv64, "sysv64");
32        #[cfg(has_abi_aapcs)]
33        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Aapcs, "aapcs");
34    };
35
36    (@impl_u_and_s ($($nm:ident : $ty:ident),*), $abi_ident:ident, $abi_str:expr) => {
37        impl_fn!(@impl_core ($($nm : $ty),*), extern $abi_str fn($($ty),*) -> Ret, true, $abi_ident, $abi_str);
38        impl_fn!(@impl_core ($($nm : $ty),*), unsafe extern $abi_str fn($($ty),*) -> Ret, false, $abi_ident, $abi_str);
39    };
40
41    (@impl_core ($($nm:ident : $ty:ident),*), $fn_type:ty, true, $abi_ident:ident, $call_conv:expr) => {
42        impl<Ret: 'static, $($ty: 'static),*> $crate::FnPtr for $fn_type {
43            type Args = ($($ty,)*);
44            type Output = Ret;
45
46            const ARITY: ::core::primitive::usize = impl_fn!(@count ($($ty)*));
47            const IS_SAFE: ::core::primitive::bool = true;
48            const IS_EXTERN: ::core::primitive::bool = !matches!($crate::Abi::$abi_ident, $crate::Abi::Rust);
49            const ABI: $crate::Abi = $crate::Abi::$abi_ident;
50        }
51        impl<Ret: 'static, $($ty: 'static),*> $crate::SafeFnPtr for $fn_type {}
52
53        // WithSafety
54        impl<Ret: 'static, $($ty: 'static),*> $crate::WithSafety<{true}, $fn_type> for $fn_type { type F = $fn_type; }
55        impl<Ret: 'static, $($ty: 'static),*> $crate::WithSafety<{false}, $fn_type> for $fn_type { type F = unsafe extern $call_conv fn($($ty),*) -> Ret; }
56
57        cfg_all!(feature = "nightly" {
58            // HasAbi
59            impl<Ret: 'static, $($ty: 'static),*> $crate::HasAbi<{$crate::Abi::$abi_ident}> for $fn_type {}
60
61            // WithAbi
62            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Rust}, $fn_type> for $fn_type { type F = extern "Rust" fn($($ty),*) -> Ret; }
63            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::C}, $fn_type> for $fn_type { type F = extern "C" fn($($ty),*) -> Ret; }
64            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::System}, $fn_type> for $fn_type { type F = extern "system" fn($($ty),*) -> Ret; }
65            #[cfg(has_abi_cdecl)]
66            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Cdecl}, $fn_type> for $fn_type { type F = extern "cdecl" fn($($ty),*) -> Ret; }
67            #[cfg(has_abi_stdcall)]
68            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Stdcall}, $fn_type> for $fn_type { type F = extern "stdcall" fn($($ty),*) -> Ret; }
69            #[cfg(has_abi_fastcall)]
70            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Fastcall}, $fn_type> for $fn_type { type F = extern "fastcall" fn($($ty),*) -> Ret; }
71            #[cfg(has_abi_win64)]
72            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Win64}, $fn_type> for $fn_type { type F = extern "win64" fn($($ty),*) -> Ret; }
73            #[cfg(has_abi_sysv64)]
74            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Sysv64}, $fn_type> for $fn_type { type F = extern "sysv64" fn($($ty),*) -> Ret; }
75            #[cfg(has_abi_aapcs)]
76            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Aapcs}, $fn_type> for $fn_type { type F = extern "aapcs" fn($($ty),*) -> Ret; }
77        });
78    };
79
80    (@impl_core ($($nm:ident : $ty:ident),*), $fn_type:ty, false, $abi_ident:ident, $call_conv:expr) => {
81        impl<Ret: 'static, $($ty: 'static),*> $crate::FnPtr for $fn_type {
82            type Args = ($($ty,)*);
83            type Output = Ret;
84
85            const ARITY: ::core::primitive::usize = impl_fn!(@count ($($ty)*));
86            const IS_SAFE: ::core::primitive::bool = false;
87            const IS_EXTERN: ::core::primitive::bool = !matches!($crate::Abi::$abi_ident, $crate::Abi::Rust);
88            const ABI: $crate::Abi = $crate::Abi::$abi_ident;
89        }
90        impl<Ret: 'static, $($ty: 'static),*> $crate::UnsafeFnPtr for $fn_type {}
91
92        // WithSafety
93        impl<Ret: 'static, $($ty: 'static),*> $crate::WithSafety<{true}, $fn_type> for $fn_type { type F = extern $call_conv fn($($ty),*) -> Ret; }
94        impl<Ret: 'static, $($ty: 'static),*> $crate::WithSafety<{false}, $fn_type> for $fn_type { type F = $fn_type; }
95
96        cfg_all!(feature = "nightly" {
97            // HasAbi
98            impl<Ret: 'static, $($ty: 'static),*> $crate::HasAbi<{$crate::Abi::$abi_ident}> for $fn_type {}
99
100            // WithAbi
101            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Rust}, $fn_type> for $fn_type { type F = unsafe extern "Rust" fn($($ty),*) -> Ret; }
102            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::C}, $fn_type> for $fn_type { type F = unsafe extern "C" fn($($ty),*) -> Ret; }
103            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::System}, $fn_type> for $fn_type { type F = unsafe extern "system" fn($($ty),*) -> Ret; }
104            #[cfg(has_abi_cdecl)]
105            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Cdecl}, $fn_type> for $fn_type { type F = unsafe extern "cdecl" fn($($ty),*) -> Ret; }
106            #[cfg(has_abi_stdcall)]
107            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Stdcall}, $fn_type> for $fn_type { type F = unsafe extern "stdcall" fn($($ty),*) -> Ret; }
108            #[cfg(has_abi_fastcall)]
109            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Fastcall}, $fn_type> for $fn_type { type F = unsafe extern "fastcall" fn($($ty),*) -> Ret; }
110            #[cfg(has_abi_win64)]
111            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Win64}, $fn_type> for $fn_type { type F = unsafe extern "win64" fn($($ty),*) -> Ret; }
112            #[cfg(has_abi_sysv64)]
113            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Sysv64}, $fn_type> for $fn_type { type F = unsafe extern "sysv64" fn($($ty),*) -> Ret; }
114            #[cfg(has_abi_aapcs)]
115            impl<Ret: 'static, $($ty: 'static),*> $crate::WithAbi<{$crate::Abi::Aapcs}, $fn_type> for $fn_type { type F = unsafe extern "aapcs" fn($($ty),*) -> Ret; }
116        });
117    };
118
119    (@count ()) => {
120        0
121    };
122    (@count ($hd:tt $($tl:tt)*)) => {
123        1 + impl_fn!(@count ($($tl)*))
124    };
125
126    ($($nm:ident : $ty:ident),*) => {
127        impl_fn!(@recurse ($($nm : $ty),*) ());
128    };
129}
130
131// Default: generate impls up to 6 arguments
132#[cfg(not(feature = "max-arity-12"))]
133impl_fn! {
134    __arg_0:  A, __arg_1:  B, __arg_2:  C, __arg_3:  D, __arg_4:  E, __arg_5:  F
135}
136
137// Optional: generate impls up to 12 arguments when feature is enabled
138#[cfg(feature = "max-arity-12")]
139impl_fn! {
140    __arg_0:  A, __arg_1:  B, __arg_2:  C, __arg_3:  D, __arg_4:  E, __arg_5:  F, __arg_6:  G,
141    __arg_7:  H, __arg_8:  I, __arg_9:  J, __arg_10: K, __arg_11: L
142}