Skip to content

OpenByteDev/fn-ptr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

About

A crate providing a function pointer trait.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages