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    // main entry point
5    ($($nm:ident : $ty:ident),*) => {
6        impl_fn!(@recurse ($($nm : $ty),*) ());
7    };
8
9    // recurse for all parameter counts
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    // call for every abi
19    (@impl_all ($($nm:ident : $ty:ident),*)) => {
20        // Always-present
21        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Rust, "Rust");
22        impl_fn!(@impl_u_and_s ($($nm : $ty),*), C, "C");
23        impl_fn!(@impl_u_and_s ($($nm : $ty),*), CUnwind, "C-unwind");
24        impl_fn!(@impl_u_and_s ($($nm : $ty),*), System, "system");
25        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SystemUnwind, "system-unwind");
26
27        // Platform-specific ABIs
28        #[cfg(has_abi_cdecl)]
29        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Cdecl, "cdecl");
30        #[cfg(has_abi_cdecl)]
31        impl_fn!(@impl_u_and_s ($($nm : $ty),*), CdeclUnwind, "cdecl-unwind");
32
33        #[cfg(has_abi_stdcall)]
34        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Stdcall, "stdcall");
35        #[cfg(has_abi_stdcall)]
36        impl_fn!(@impl_u_and_s ($($nm : $ty),*), StdcallUnwind, "stdcall-unwind");
37
38        #[cfg(has_abi_fastcall)]
39        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Fastcall, "fastcall");
40        #[cfg(has_abi_fastcall)]
41        impl_fn!(@impl_u_and_s ($($nm : $ty),*), FastcallUnwind, "fastcall-unwind");
42
43        #[cfg(has_abi_thiscall)]
44        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Thiscall, "thiscall");
45        #[cfg(has_abi_thiscall)]
46        impl_fn!(@impl_u_and_s ($($nm : $ty),*), ThiscallUnwind, "thiscall-unwind");
47
48        #[cfg(has_abi_vectorcall)]
49        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Vectorcall, "vectorcall");
50        #[cfg(has_abi_vectorcall)]
51        impl_fn!(@impl_u_and_s ($($nm : $ty),*), VectorcallUnwind, "vectorcall-unwind");
52
53        #[cfg(has_abi_win64)]
54        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Win64, "win64");
55        #[cfg(has_abi_win64)]
56        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Win64Unwind, "win64-unwind");
57
58        #[cfg(has_abi_sysv64)]
59        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SysV64, "sysv64");
60        #[cfg(has_abi_sysv64)]
61        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SysV64Unwind, "sysv64-unwind");
62
63        #[cfg(has_abi_aapcs)]
64        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Aapcs, "aapcs");
65        #[cfg(has_abi_aapcs)]
66        impl_fn!(@impl_u_and_s ($($nm : $ty),*), AapcsUnwind, "aapcs-unwind");
67
68        #[cfg(has_abi_efiapi)]
69        impl_fn!(@impl_u_and_s ($($nm : $ty),*), EfiApi, "efiapi");
70    };
71
72    // call for safe and unsafe
73    (@impl_u_and_s ($($nm:ident : $ty:ident),*), $abi_ident:ident, $abi_str:expr) => {
74        impl_fn!(@impl_core ($($nm : $ty),*), extern $abi_str fn($($ty),*) -> Output, true, $abi_ident, $abi_str);
75        impl_fn!(@impl_core ($($nm : $ty),*), unsafe extern $abi_str fn($($ty),*) -> Output, false, $abi_ident, $abi_str);
76    };
77
78    // core macro
79    (@impl_core ($($nm:ident : $ty:ident),*), $fn_type:ty, $safety:tt, $abi_ident:ident, $call_conv:expr) => {
80        #[automatically_derived]
81        impl<Output, $($ty),*> $crate::FnPtr for $fn_type {
82            type Args = ($($ty,)*);
83            type Output = Output;
84
85            type Safety = $crate::safety!($safety);
86            type Abi = $crate::abi::$abi_ident;
87
88            const ARITY: ::core::primitive::usize = <<Self::Args as $crate::tuple::Tuple>::Arity as $crate::arity::Arity>::N;
89            const IS_SAFE: ::core::primitive::bool = <Self::Safety as $crate::safety::Safety>::IS_SAFE;
90            const ABI: $crate::AbiValue = <$crate::abi::$abi_ident as $crate::abi::Abi>::VALUE;
91            const IS_EXTERN: ::core::primitive::bool = !matches!(Self::ABI, $crate::AbiValue::Rust);
92
93            fn as_ptr(&self) -> $crate::UntypedFnPtr {
94                *self as $crate::UntypedFnPtr
95            }
96            unsafe fn from_ptr(ptr: $crate::UntypedFnPtr) -> Self {
97                ::core::assert!(!ptr.is_null());
98                unsafe { ::core::mem::transmute::<$crate::UntypedFnPtr, Self>(ptr) }
99            }
100        }
101        impl_fn!(@impl_safe_fn_type ($($nm : $ty),*), $fn_type, $safety);
102
103        #[automatically_derived]
104        impl<Output, $($ty),*> $crate::BuildFn<$crate::safety!($safety), $crate::abi::$abi_ident, Output> for ($($ty,)*) {
105            type F = impl_fn!(@make_unsafe extern $call_conv fn($($ty),*) -> Output, $safety);
106        }
107
108        // WithSafetyFrom
109        #[automatically_derived]
110        impl<Output, $($ty),*> $crate::WithSafetyImpl<$crate::safety::Safe> for $fn_type {
111            type F = extern $call_conv fn($($ty),*) -> Output;
112        }
113        #[automatically_derived]
114        impl<Output, $($ty),*> $crate::WithSafetyImpl<$crate::safety::Unsafe> for $fn_type {
115            type F = unsafe extern $call_conv fn($($ty),*) -> Output;
116        }
117
118        // WithArgsFrom
119        #[automatically_derived]
120        impl<Output, $($ty),*> $crate::WithArgsImpl<$fn_type> for $fn_type {
121            type F<Args: $crate::Tuple> = <<<Args::BaseFn as $crate::WithSafety<$crate::safety!($safety)>>::F as $crate::WithAbi<$crate::abi::$abi_ident>>::F as $crate::WithOutput<Output>>::F;
122        }
123
124        // WithRetFrom
125        #[automatically_derived]
126        impl<Output, $($ty),*> $crate::WithOutputImpl for $fn_type {
127            type F<R> = impl_fn!(@make_unsafe extern $call_conv fn($($ty),*) -> R, $safety);
128        }
129
130        // WithAbi
131        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "Rust");
132        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "C");
133        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "system");
134        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "C-unwind");
135        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "system-unwind");
136
137        #[cfg(has_abi_cdecl)]
138        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "cdecl");
139        #[cfg(has_abi_cdecl)]
140        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "cdecl-unwind");
141
142        #[cfg(has_abi_stdcall)]
143        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "stdcall");
144        #[cfg(has_abi_stdcall)]
145        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "stdcall-unwind");
146
147        #[cfg(has_abi_fastcall)]
148        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "fastcall");
149        #[cfg(has_abi_fastcall)]
150        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "fastcall-unwind");
151
152        #[cfg(has_abi_thiscall)]
153        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "thiscall");
154        #[cfg(has_abi_thiscall)]
155        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "thiscall-unwind");
156
157        #[cfg(has_abi_vectorcall)]
158        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "vectorcall");
159        #[cfg(has_abi_vectorcall)]
160        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "vectorcall-unwind");
161
162        #[cfg(has_abi_win64)]
163        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "win64");
164        #[cfg(has_abi_win64)]
165        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "win64-unwind");
166
167        #[cfg(has_abi_sysv64)]
168        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "sysv64");
169        #[cfg(has_abi_sysv64)]
170        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "sysv64-unwind");
171
172        #[cfg(has_abi_aapcs)]
173        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "aapcs");
174        #[cfg(has_abi_aapcs)]
175        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "aapcs-unwind");
176
177        #[cfg(has_abi_efiapi)]
178        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "efiapi");
179    };
180
181    (@impl_withabi ($($nm:ident : $ty:ident),*), $fn_type:ty, $safety:tt, $abi:tt) => {
182        #[automatically_derived]
183        impl<Output, $($ty),*> $crate::WithAbiImpl<$crate::abi!($abi)> for $fn_type {
184            type F = impl_fn!(@make_unsafe extern $abi fn($($ty),*) -> Output, $safety);
185        }
186    };
187
188    (@make_unsafe $fn_type:ty, true) => { $fn_type };
189    (@make_unsafe extern $abi:literal fn($($args:ty),*) -> $Output:ty, false) => {
190        unsafe extern $abi fn($($args),*) -> $Output
191    };
192
193    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, true) => {
194        #[automatically_derived]
195        impl<Output, $($ty),*> $crate::SafeFnPtr for $fn_type {
196            fn invoke(&self, ($($nm,)*): Self::Args) -> Self::Output {
197                (*self)($($nm),*)
198            }
199        }
200    };
201    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, false) => {
202        #[automatically_derived]
203        impl<Output, $($ty),*> $crate::UnsafeFnPtr for $fn_type {
204            unsafe fn invoke(&self, ($($nm,)*): Self::Args) -> Self::Output {
205                unsafe { (*self)($($nm),*) }
206            }
207        }
208    };
209}
210
211// Default: generate impls up to 6 arguments
212#[cfg(not(feature = "max-arity-12"))]
213impl_fn! {
214    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F
215}
216
217// Optional: generate impls up to 12 arguments when feature is enabled
218#[cfg(feature = "max-arity-12")]
219impl_fn! {
220    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F, __arg_6: G,
221    __arg_7: H, __arg_8: I, __arg_9: J, __arg_10: K, __arg_11: L
222}