ffi_closure/
cc.rs

1#![allow(non_snake_case)]
2
3use super::Closure;
4use alloc::boxed::Box;
5use core::ffi::c_void;
6#[allow(unused_imports)]
7use docfg::docfg;
8
9pub trait CallingConvention: sealed::Sealed {
10    type Destructor: Copy;
11
12    unsafe fn destroy(f: Self::Destructor, user_data: *mut c_void);
13}
14
15pub trait AsExtern<Cc: CallingConvention>: sealed::Sealed {
16    type Args;
17    type Extern: Copy;
18    type Output;
19
20    unsafe fn call_mut(f: Self::Extern, args: Self::Args, user_data: *mut c_void) -> Self::Output;
21}
22
23pub trait IntoExtern<Ext: ?Sized + AsExtern<Cc>, Cc: CallingConvention> {
24    fn into_extern(self: Box<Self>) -> Closure<Ext, Cc>;
25}
26
27macro_rules! impl_ {
28    (
29        $abi:literal as $ident:ident => ($($arg:ident),*) $(+ $($trait:ident),+)?
30    ) => {
31        impl<'a, $($arg,)* __OUT__> AsExtern<$ident> for dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__ {
32            type Args = ($($arg,)*);
33            type Extern = unsafe extern $abi fn($($arg,)* *mut c_void) -> __OUT__;
34            type Output = __OUT__;
35
36            #[inline(always)]
37            unsafe fn call_mut(f: Self::Extern, ($($arg,)*): ($($arg,)*), user_data: *mut c_void) -> Self::Output {
38                (f)($($arg,)* user_data)
39            }
40        }
41
42        impl<'a, $($arg,)* __F__: 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, __OUT__> IntoExtern<dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, $ident> for __F__ {
43            #[inline]
44            fn into_extern(self: Box<Self>) -> Closure<dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, $ident> {
45                unsafe extern $abi fn call<$($arg,)* __F__: FnMut($($arg,)*) -> __OUT__, __OUT__>($($arg: $arg,)* user_data: *mut c_void) -> __OUT__ {
46                    return (&mut *user_data.cast::<__F__>())($($arg),*)
47                }
48
49                unsafe extern $abi fn destroy<__F__>(user_data: *mut c_void) {
50                    drop(Box::from_raw(user_data.cast::<__F__>()))
51                }
52
53                let user_data = Box::into_raw(self).cast();
54                return unsafe {
55                    Closure::from_extern(
56                        call::<$($arg,)* Self, __OUT__> as unsafe extern $abi fn($($arg,)* *mut c_void) -> __OUT__,
57                        user_data,
58                        Some(destroy::<Self> as unsafe extern $abi fn(*mut c_void))
59                    )
60                }
61            }
62        }
63    }
64}
65
66macro_rules! impl_fn {
67    (
68        $(#[cfg($cfg:meta)])?
69        $abi:literal as $ident:ident {
70            $(
71                ($($arg:ident),*)
72            ),+ $(,)?
73        }
74    ) => {
75        $(
76            impl_! { $abi as $ident => ($($arg),*) }
77            impl_! { $abi as $ident => ($($arg),*) + Send }
78            impl_! { $abi as $ident => ($($arg),*) + Sync }
79            impl_! { $abi as $ident => ($($arg),*) + Send, Sync }
80        )+
81    };
82}
83
84macro_rules! cc {
85    ($($(#[cfg($cfg:meta)])? $abi:literal as $ident:ident),+ $(,)?) => {
86        $(
87            $(
88                #[cfg(any(docsrs, $cfg))]
89                #[cfg_attr(docsrs, doc(cfg($cfg)))]
90            )?
91            #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
92            #[doc = concat!("The \"", $abi, "\" calling convention")]
93            pub struct $ident;
94
95            $(
96                #[cfg(any(docsrs, $cfg))]
97                #[cfg_attr(docsrs, doc(cfg($cfg)))]
98            )?
99            impl CallingConvention for $ident {
100                type Destructor = unsafe extern $abi fn(*mut c_void);
101
102                #[inline(always)]
103                unsafe fn destroy(f: Self::Destructor, user_data: *mut c_void) {
104                    (f)(user_data)
105                }
106            }
107
108            $(
109                #[cfg(any(docsrs, $cfg))]
110                #[cfg_attr(docsrs, doc(cfg($cfg)))]
111            )?
112            impl sealed::Sealed for $ident {}
113
114            $(
115                #[cfg(any(docsrs, $cfg))]
116                #[cfg_attr(docsrs, doc(cfg($cfg)))]
117            )?
118            impl_fn! {
119                $abi as $ident {
120                    (),
121                    (A),
122                    (A, B),
123                    (A, B, C_),
124                    (A, B, C_, D),
125                    (A, B, C_, D, E),
126                    (A, B, C_, D, E, F),
127                    (A, B, C_, D, E, F, G),
128                    (A, B, C_, D, E, F, G, H),
129                    (A, B, C_, D, E, F, G, H, I),
130                    (A, B, C_, D, E, F, G, H, I, J),
131                    (A, B, C_, D, E, F, G, H, I, J, K),
132                    (A, B, C_, D, E, F, G, H, I, J, K, L),
133                    (A, B, C_, D, E, F, G, H, I, J, K, L, M),
134                    (A, B, C_, D, E, F, G, H, I, J, K, L, M, N),
135                }
136            }
137        )+
138    };
139}
140
141macro_rules! seal {
142    (
143        $(
144            ($($arg:ident),*)
145        ),+ $(,)?
146    ) => {
147        $(
148            impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + FnMut($($arg,)*) -> __OUT__ {}
149            impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Send + FnMut($($arg,)*) -> __OUT__ {}
150            impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Sync + FnMut($($arg,)*) -> __OUT__ {}
151            impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Send + Sync + FnMut($($arg,)*) -> __OUT__ {}
152        )+
153    };
154}
155
156// https://doc.rust-lang.org/nomicon/ffi.html#foreign-calling-conventions
157cc! {
158    #[cfg(any(target_arch = "x86"))]
159    "stdcall" as StdCall,
160    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
161    "aapcs" as Aapcs,
162    "cdecl" as Cdecl,
163    #[cfg(any(target_arch = "x86"))]
164    "fastcall" as FastCall,
165    #[cfg(any(target_arch = "x86"))]
166    "thiscall" as ThisCall,
167    "Rust" as Rust,
168    "system" as System,
169    "C" as C,
170    #[cfg(all(windows, any(target_arch = "x86_64", target_arch = "aarch64")))]
171    "win64" as Win64,
172    #[cfg(any(target_arch = "x86_64"))]
173    "sysv64" as Sysv64
174}
175
176seal! {
177    (),
178    (A),
179    (A, B),
180    (A, B, C_),
181    (A, B, C_, D),
182    (A, B, C_, D, E),
183    (A, B, C_, D, E, F),
184    (A, B, C_, D, E, F, G),
185    (A, B, C_, D, E, F, G, H),
186    (A, B, C_, D, E, F, G, H, I),
187    (A, B, C_, D, E, F, G, H, I, J),
188    (A, B, C_, D, E, F, G, H, I, J, K),
189    (A, B, C_, D, E, F, G, H, I, J, K, L),
190    (A, B, C_, D, E, F, G, H, I, J, K, L, M),
191    (A, B, C_, D, E, F, G, H, I, J, K, L, M, N),
192}
193
194mod sealed {
195    pub trait Sealed {}
196}