fn_ptr/
impl.rs

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