fn-ptr 0.4.0

A crate providing function pointer traits.
Documentation

fn-ptr

CI crates.io Documentation dependency status MIT

This is a small utility crate that provides the FnPtr trait, which is implemented for all function pointer types:

  • fn(T) -> U
  • unsafe fn(T) -> U
  • extern "C" fn(T)
  • unsafe extern "sysv64" fn() -> i32

The trait provides associated types and constants to introspect function pointer types at compile time.

Features

1. Function Pointer Metadata

Every function pointer automatically implements FnPtr. Depending on the type, they also implement SafeFnPtr,, UnsafeFnPtr, and HasAbi<Abi>. With it you can inspect the type of function:

use fn_ptr::{FnPtr, Abi};

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, Abi::C);

There are also some const helper functons to do so ergonomically.

const A: usize = fn_ptr::arity::<F>();         // 2
const SAFE: bool = fn_ptr::is_safe::<F>();     // true
const EXT: bool = fn_ptr::is_extern::<F>();    // true
const ABI: Abi = fn_ptr::abi::<F>();           // Abi::C

2. Toggle Function Pointer Safety

You can toggle the safety of a function pointer at the type level:

use fn_ptr::{make_safe, make_unsafe};

type U = unsafe extern "C" fn(i32);
type S = make_safe!(U);       // extern "C" fn(i32)

type S2 = extern "C" fn(i32);
type U2 = make_unsafe!(S2);   // unsafe extern "C" fn(i32)

Or at the instance level:

let safe_add: fn(i32, i32) -> i32 = |a, b| {a + b};
let unsafe_add: unsafe fn(i32, i32) -> i32 = safe_add.as_unsafe();
let safe_add2: fn(i32, i32) -> i32 = unsafe { unsafe_add.as_safe() };

3. Changing ABIs

You can also change the ABI of a function pointer at the type level:

use fn_ptr::{with_abi, Abi};

type F = extern "C" fn(i32) -> i32;

type G = with_abi!(Abi::Sysv64, F);
type H = with_abi!("C", extern "system" fn());

Or at the instance level:

use fn_ptr::{FnPtr, abi};
let rust_add: fn(i32, i32) -> i32 = |a, b| {a + b};
// Safety: not actually safe!
let c_add: extern "C" fn(i32, i32) -> i32 = unsafe { rust_add.with_abi::<{abi!("C")}>() };

Note that this does not change the underlying ABI and should be used with caution.

How It Works

To implement the traits for all function pointer types, there is a large macro. For the conversion macros the crate relies on two traits: WithAbi and WithSafety that can also be used directly:

use fn_ptr::{FnPtr, WithAbi, WithSafety, Abi};

type F = extern "C" fn(i32);
type G = <F as WithAbi<{Abi::Sysv64}>>::F;
type U = <F as WithSafety<{false}>>::F;

License

Licensed under the MIT license, see LICENSE for details.