This is a utility crate for introspecting and rewriting function pointer types at compile time.
It implements FnPtr for all function-pointer types:
fn(T) -> Uunsafe fn(T) -> Uextern "C-unwind" fn(T)unsafe extern "sysv64" fn() -> i32
FnPtr exposes metadata as associated types/consts.
use fn_ptr::{FnPtr, AbiValue};
type F = extern "C" fn(i32, i32) -> i32;
assert_eq!(<F as FnPtr>::ARITY, 2);
assert_eq!(<F as FnPtr>::IS_SAFE, true);
assert_eq!(<F as FnPtr>::IS_EXTERN, true);
assert_eq!(<F as FnPtr>::ABI, AbiValue::C { unwind: false });Ergonomic const functions are provided as well:
const A: usize = fn_ptr::arity::<F>();
const SAFE: bool = fn_ptr::is_safe::<F>();
const EXT: bool = fn_ptr::is_extern::<F>();
const abi: AbiValue = fn_ptr::abi::<F>();The crate provides type-level rewriting via traits:
- abi:
WithAbi/with_abi! - Safety:
WithSafety/with_safety!(make_safe!,make_unsafe!) - Output:
WithOutput/with_output! - Args:
WithArgs/with_args!
The macros compute a new function-pointer type while preserving everything else.
use fn_ptr::{with_abi, with_safety, with_output, with_args};
type F = extern "C" fn(i32) -> i32;
type F1 = with_abi!("sysv64", F); // extern "sysv64" fn(i32) -> i32
type F2 = with_safety!(unsafe, F); // unsafe extern "C" fn(i32) -> i32
type F3 = with_output!(u64, F); // extern "C" fn(i32) -> u64
type F4 = with_args!((u8, u16), F); // extern "C" fn(u8, u16) -> i32The same transformations exist at the value level via methods on FnPtr.
These casts are only transmuting and do not the actual underlying function.
use fn_ptr::{FnPtr, abi};
let f: fn(i32, i32) -> i32 = |a, b| a + b;
// safety
let u: unsafe fn(i32, i32) -> i32 = f.as_unsafe();
let f2: fn(i32, i32) -> i32 = unsafe { u.as_safe() };
// abi
let c: extern "C" fn(i32, i32) -> i32 = unsafe { f.with_abi::<abi!("C")>() };
// output
let out: fn(i32, i32) -> u64 = unsafe { f.with_output::<u64>() };
// args
let args: fn(u8, u16) -> i32 = unsafe { f.with_args::<(u8, u16)>() };
# assert_eq!(f.addr(), f2.addr());
# assert_eq!(f.addr(), c.addr());
# assert_eq!(f.addr(), out.addr());
# assert_eq!(f.addr(), args.addr());Implementations are generated by a large macro. The rewrite macros are thin wrappers
over the traits WithAbi, WithSafety, WithOutput, WithArgs (and the corresponding *Impl helper traits).
Licensed under the MIT license, see LICENSE for details.