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, $($ty),*> $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        #[automatically_derived]
57        impl<Ret: 'static, $($ty: 'static),*> $crate::StaticFnPtr for $fn_type {
58        }
59
60        // WithSafety
61        #[automatically_derived]
62        impl<Ret, $($ty),*> $crate::WithSafety<{true}> for $fn_type {
63            type F = extern $call_conv fn($($ty),*) -> Ret;
64        }
65        #[automatically_derived]
66        impl<Ret, $($ty),*> $crate::WithSafety<{false}> for $fn_type {
67            type F = unsafe extern $call_conv fn($($ty),*) -> Ret;
68        }
69
70        // HasAbi
71        #[automatically_derived]
72        impl<Ret, $($ty),*> $crate::HasAbi<{$crate::abi!($call_conv)}> for $fn_type {}
73
74        // WithAbi
75        #[automatically_derived]
76        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("Rust")}> for $fn_type {
77            type F = impl_fn!(@make_unsafe extern "Rust" fn($($ty),*) -> Ret, $safety);
78        }
79        #[automatically_derived]
80        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("C")}> for $fn_type {
81            type F = impl_fn!(@make_unsafe extern "C" fn($($ty),*) -> Ret, $safety);
82        }
83        #[automatically_derived]
84        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("system")}> for $fn_type {
85            type F = impl_fn!(@make_unsafe extern "system" fn($($ty),*) -> Ret, $safety);
86        }
87        #[cfg(has_abi_cdecl)]
88        #[automatically_derived]
89        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("cdecl")}> for $fn_type {
90            type F = impl_fn!(@make_unsafe extern "cdecl" fn($($ty),*) -> Ret, $safety);
91        }
92        #[cfg(has_abi_stdcall)]
93        #[automatically_derived]
94        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("stdcall")}> for $fn_type {
95            type F = impl_fn!(@make_unsafe extern "stdcall" fn($($ty),*) -> Ret, $safety);
96        }
97        #[cfg(has_abi_fastcall)]
98        #[automatically_derived]
99        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("fastcall")}> for $fn_type {
100            type F = impl_fn!(@make_unsafe extern "fastcall" fn($($ty),*) -> Ret, $safety);
101        }
102        #[cfg(has_abi_win64)]
103        #[automatically_derived]
104        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("win64")}> for $fn_type {
105            type F = impl_fn!(@make_unsafe extern "win64" fn($($ty),*) -> Ret, $safety);
106        }
107        #[cfg(has_abi_sysv64)]
108        #[automatically_derived]
109        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("sysv64")}> for $fn_type {
110            type F = impl_fn!(@make_unsafe extern "sysv64" fn($($ty),*) -> Ret, $safety);
111        }
112        #[cfg(has_abi_aapcs)]
113        #[automatically_derived]
114        impl<Ret, $($ty),*> $crate::WithAbi<{$crate::abi!("aapcs")}> for $fn_type {
115            type F = impl_fn!(@make_unsafe extern "aapcs" fn($($ty),*) -> Ret, $safety);
116        }
117    };
118
119    (@count ()) => {
120        0
121    };
122    (@count ($hd:tt $($tl:tt)*)) => {
123        1 + impl_fn!(@count ($($tl)*))
124    };
125
126    (@make_unsafe $fn_type:ty, true) => {
127        $fn_type
128    };
129    (@make_unsafe extern $abi:literal fn($($args:ty),*) -> $ret:ty, false) => {
130        unsafe extern $abi fn($($args),*) -> $ret
131    };
132
133    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, true) => {
134        #[automatically_derived]
135        impl<Ret, $($ty),*> $crate::SafeFnPtr for $fn_type {
136            fn invoke(&self, impl_fn!(@call_args ($($nm),*)): Self::Args) -> Self::Output {
137                (*self)($($nm),*)
138            }
139        }
140     };
141    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, false) => {
142        #[automatically_derived]
143        impl<Ret, $($ty),*> $crate::UnsafeFnPtr for $fn_type {
144            unsafe fn invoke(&self, impl_fn!(@call_args ($($nm),*)): Self::Args) -> Self::Output {
145                unsafe { (*self)($($nm),*) }
146            }
147        }
148    };
149
150    (@call_args ($single:ident)) => {
151        ($single,)
152    };
153    (@call_args ($($args:ident),*)) => {
154        ($($args),*)
155    };
156
157    ($($nm:ident : $ty:ident),*) => {
158        impl_fn!(@recurse ($($nm : $ty),*) ());
159    };
160}
161
162// Default: generate impls up to 6 arguments
163#[cfg(not(feature = "max-arity-12"))]
164impl_fn! {
165    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F
166}
167
168// Optional: generate impls up to 12 arguments when feature is enabled
169#[cfg(feature = "max-arity-12")]
170impl_fn! {
171    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F, __arg_6: G,
172    __arg_7: H, __arg_8: I, __arg_9: J, __arg_10: K, __arg_11: L
173}