1use std::{fmt::Display, str::FromStr};
2
3use winapi::shared::minwindef::{__some_function, FARPROC};
4
5pub type RawFunctionPtr = FARPROC;
7pub type RawFunctionPtrTarget = __some_function;
9
10pub unsafe trait FunctionPtr: Sized + Copy + Send + Sync + 'static {
15 type Args;
17
18 type RefArgs<'a>;
20
21 type Output;
23
24 type NonExtern: FunctionPtr;
26
27 const ARITY: usize;
29
30 const ABI: Abi;
32
33 unsafe fn from_ptr(ptr: RawFunctionPtr) -> Self;
39
40 fn as_ptr(&self) -> RawFunctionPtr;
42}
43
44#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
45pub enum Abi {
47 Rust,
49 C,
51 System,
53 Win64,
55 Sysv64,
57 Aapcs,
59 Cdecl,
61 Stdcall,
63 Fastcall,
65 Vectorcall,
67}
68
69impl Abi {
70 #[must_use]
72 pub const fn to_str(&self) -> &'static str {
73 match self {
74 Abi::Rust => "Rust",
75 Abi::C => "C",
76 Abi::System => "System",
77 Abi::Win64 => "Win64",
78 Abi::Sysv64 => "Sysv64",
79 Abi::Aapcs => "Aapcs",
80 Abi::Cdecl => "Cdecl",
81 Abi::Stdcall => "Stdcall",
82 Abi::Fastcall => "Fastcall",
83 Abi::Vectorcall => "Vectorcall",
84 }
85 }
86}
87
88impl FromStr for Abi {
89 type Err = ();
90
91 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 match s {
93 "" | "Rust" => Ok(Abi::C),
94 "C" => Ok(Abi::C),
95 "system" => Ok(Abi::System),
96 "win64" => Ok(Abi::Win64),
97 "sysv64" => Ok(Abi::Sysv64),
98 "aapcs" => Ok(Abi::Aapcs),
99 "cdecl" => Ok(Abi::Cdecl),
100 "stdcall" => Ok(Abi::Stdcall),
101 "fastcall" => Ok(Abi::Fastcall),
102 "vectorcall" => Ok(Abi::Vectorcall),
103 _ => Err(()),
104 }
105 }
106}
107
108#[must_use]
109const fn call_conv_from_str(conv: &'static str) -> Option<Abi> {
110 if konst::eq_str(conv, "") || konst::eq_str(conv, "Rust") {
111 Some(Abi::Rust)
112 } else if konst::eq_str(conv, "C") {
113 Some(Abi::C)
114 } else if konst::eq_str(conv, "system") {
115 Some(Abi::System)
116 } else if konst::eq_str(conv, "win64") {
117 Some(Abi::Win64)
118 } else if konst::eq_str(conv, "sysv64") {
119 Some(Abi::Sysv64)
120 } else if konst::eq_str(conv, "aapcs") {
121 Some(Abi::Aapcs)
122 } else if konst::eq_str(conv, "cdecl") {
123 Some(Abi::Cdecl)
124 } else if konst::eq_str(conv, "stdcall") {
125 Some(Abi::Stdcall)
126 } else if konst::eq_str(conv, "fastcall") {
127 Some(Abi::Fastcall)
128 } else if konst::eq_str(conv, "vectorcall") {
129 Some(Abi::Vectorcall)
130 } else {
131 None
132 }
133}
134
135impl Display for Abi {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 write!(f, "{}", self.to_str())
138 }
139}
140
141macro_rules! impl_fn {
142 (@recurse () ($($nm:ident : $ty:ident),*)) => {
143 impl_fn!(@impl_all ($($nm : $ty),*));
144 };
145 (@recurse ($hd_nm:ident : $hd_ty:ident $(, $tl_nm:ident : $tl_ty:ident)*) ($($nm:ident : $ty:ident),*)) => {
146 impl_fn!(@impl_all ($($nm : $ty),*));
147 impl_fn!(@recurse ($($tl_nm : $tl_ty),*) ($($nm : $ty,)* $hd_nm : $hd_ty));
148 };
149
150 (@impl_all ($($nm:ident : $ty:ident),*)) => {
151 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("Rust") fn($($ty),*) -> Ret);
153 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("C") fn($($ty),*) -> Ret);
154 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("system") fn($($ty),*) -> Ret);
155
156 #[cfg(target_arch = "x86")]
158 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("cdecl") fn($($ty),*) -> Ret);
159 #[cfg(target_arch = "x86")]
160 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("stdcall") fn($($ty),*) -> Ret);
161 #[cfg(target_arch = "x86")]
162 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("fastcall") fn($($ty),*) -> Ret);
163
164 #[cfg(all(target_arch = "x86_64", target_os = "windows"))]
166 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("win64") fn($($ty),*) -> Ret);
167
168 #[cfg(all(target_arch = "x86_64", not(target_os = "windows")))]
170 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("sysv64") fn($($ty),*) -> Ret);
171
172 #[cfg(any(target_arch = "arm"))]
174 impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("aapcs") fn($($ty),*) -> Ret);
175 };
176
177 (@impl_u_and_s ($($nm:ident : $ty:ident),*) ($call_conv:expr) fn($($param_ty:ident),*) -> $ret:ty) => {
178 impl_fn!(@impl_core ($($nm : $ty),*) (extern $call_conv fn($($param_ty),*) -> $ret) (false) ($call_conv));
179 impl_fn!(@impl_core ($($nm : $ty),*) (unsafe extern $call_conv fn($($param_ty),*) -> $ret) (true) ($call_conv));
180 };
181
182 (@impl_core ($($nm:ident : $ty:ident),*) ($fn_type:ty) ($is_unsafe:expr) ($call_conv:expr)) => {
183 unsafe impl<Ret: 'static, $($ty: 'static),*> crate::function::FunctionPtr for $fn_type {
184 type Args = ($($ty,)*);
185 type RefArgs<'a> = ($(&'a $ty,)*);
186 type Output = Ret;
187 type NonExtern = fn($($ty),*) -> Ret;
188
189 const ARITY: ::core::primitive::usize = impl_fn!(@count ($($ty)*));
190 const ABI: crate::function::Abi = match call_conv_from_str($call_conv) {
191 Some(c) => c,
192 None => panic!(concat!("invalid or unknown abi: ", $call_conv)),
193 };
194
195 unsafe fn from_ptr(ptr: crate::function::RawFunctionPtr) -> Self {
196 ::core::assert!(!ptr.is_null());
197 unsafe { ::core::mem::transmute(ptr) }
198 }
199
200 fn as_ptr(&self) -> crate::function::RawFunctionPtr {
201 *self as crate::function::RawFunctionPtr
202 }
203 }
204 };
205
206 (@count ()) => {
207 0
208 };
209 (@count ($hd:tt $($tl:tt)*)) => {
210 1 + impl_fn!(@count ($($tl)*))
211 };
212
213 ($($nm:ident : $ty:ident),*) => {
214 impl_fn!(@recurse ($($nm : $ty),*) ());
215 };
216}
217
218impl_fn! {
219 __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F, __arg_6: G,
220 __arg_7: H, __arg_8: I, __arg_9: J, __arg_10: K, __arg_11: L
221}