use std::{fmt::Display, str::FromStr};
use winapi::shared::minwindef::{__some_function, FARPROC};
pub type RawFunctionPtr = FARPROC;
pub type RawFunctionPtrTarget = __some_function;
pub unsafe trait FunctionPtr: Sized + Copy + Send + Sync + 'static {
type Args;
type RefArgs<'a>;
type Output;
type NonExtern: FunctionPtr;
const ARITY: usize;
const ABI: Abi;
unsafe fn from_ptr(ptr: RawFunctionPtr) -> Self;
fn as_ptr(&self) -> RawFunctionPtr;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Abi {
Rust,
C,
System,
Win64,
Sysv64,
Aapcs,
Cdecl,
Stdcall,
Fastcall,
Vectorcall,
}
impl Abi {
#[must_use]
pub const fn to_str(&self) -> &'static str {
match self {
Abi::Rust => "Rust",
Abi::C => "C",
Abi::System => "System",
Abi::Win64 => "Win64",
Abi::Sysv64 => "Sysv64",
Abi::Aapcs => "Aapcs",
Abi::Cdecl => "Cdecl",
Abi::Stdcall => "Stdcall",
Abi::Fastcall => "Fastcall",
Abi::Vectorcall => "Vectorcall",
}
}
}
impl FromStr for Abi {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"" | "Rust" => Ok(Abi::C),
"C" => Ok(Abi::C),
"system" => Ok(Abi::System),
"win64" => Ok(Abi::Win64),
"sysv64" => Ok(Abi::Sysv64),
"aapcs" => Ok(Abi::Aapcs),
"cdecl" => Ok(Abi::Cdecl),
"stdcall" => Ok(Abi::Stdcall),
"fastcall" => Ok(Abi::Fastcall),
"vectorcall" => Ok(Abi::Vectorcall),
_ => Err(()),
}
}
}
#[must_use]
const fn call_conv_from_str(conv: &'static str) -> Option<Abi> {
if konst::eq_str(conv, "") || konst::eq_str(conv, "Rust") {
Some(Abi::Rust)
} else if konst::eq_str(conv, "C") {
Some(Abi::C)
} else if konst::eq_str(conv, "system") {
Some(Abi::System)
} else if konst::eq_str(conv, "win64") {
Some(Abi::Win64)
} else if konst::eq_str(conv, "sysv64") {
Some(Abi::Sysv64)
} else if konst::eq_str(conv, "aapcs") {
Some(Abi::Aapcs)
} else if konst::eq_str(conv, "cdecl") {
Some(Abi::Cdecl)
} else if konst::eq_str(conv, "stdcall") {
Some(Abi::Stdcall)
} else if konst::eq_str(conv, "fastcall") {
Some(Abi::Fastcall)
} else if konst::eq_str(conv, "vectorcall") {
Some(Abi::Vectorcall)
} else {
None
}
}
impl Display for Abi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_str())
}
}
macro_rules! impl_fn {
(@recurse () ($($nm:ident : $ty:ident),*)) => {
impl_fn!(@impl_all ($($nm : $ty),*));
};
(@recurse ($hd_nm:ident : $hd_ty:ident $(, $tl_nm:ident : $tl_ty:ident)*) ($($nm:ident : $ty:ident),*)) => {
impl_fn!(@impl_all ($($nm : $ty),*));
impl_fn!(@recurse ($($tl_nm : $tl_ty),*) ($($nm : $ty,)* $hd_nm : $hd_ty));
};
(@impl_all ($($nm:ident : $ty:ident),*)) => {
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("Rust") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("cdecl") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("stdcall") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("fastcall") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("win64") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("sysv64") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("aapcs") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("C") fn($($ty),*) -> Ret);
impl_fn!(@impl_u_and_s ($($nm : $ty),*) ("system") fn($($ty),*) -> Ret);
};
(@impl_u_and_s ($($nm:ident : $ty:ident),*) ($call_conv:expr) fn($($param_ty:ident),*) -> $ret:ty) => {
impl_fn!(@impl_core ($($nm : $ty),*) (extern $call_conv fn($($param_ty),*) -> $ret) (false) ($call_conv));
impl_fn!(@impl_core ($($nm : $ty),*) (unsafe extern $call_conv fn($($param_ty),*) -> $ret) (true) ($call_conv));
};
(@impl_core ($($nm:ident : $ty:ident),*) ($fn_type:ty) ($is_unsafe:expr) ($call_conv:expr)) => {
unsafe impl<Ret: 'static, $($ty: 'static),*> crate::function::FunctionPtr for $fn_type {
type Args = ($($ty,)*);
type RefArgs<'a> = ($(&'a $ty,)*);
type Output = Ret;
type NonExtern = fn($($ty),*) -> Ret;
const ARITY: ::core::primitive::usize = impl_fn!(@count ($($ty)*));
const ABI: crate::function::Abi = match call_conv_from_str($call_conv) {
Some(c) => c,
None => panic!(concat!("invalid or unknown abi: ", $call_conv)),
};
unsafe fn from_ptr(ptr: crate::function::RawFunctionPtr) -> Self {
::core::assert!(!ptr.is_null());
unsafe { ::core::mem::transmute(ptr) }
}
fn as_ptr(&self) -> crate::function::RawFunctionPtr {
*self as crate::function::RawFunctionPtr
}
}
};
(@count ()) => {
0
};
(@count ($hd:tt $($tl:tt)*)) => {
1 + impl_fn!(@count ($($tl)*))
};
($($nm:ident : $ty:ident),*) => {
impl_fn!(@recurse ($($nm : $ty),*) ());
};
}
impl_fn! {
__arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F, __arg_6: G,
__arg_7: H, __arg_8: I, __arg_9: J, __arg_10: K, __arg_11: L
}