fn_ptr/
base.rs

1use core::{
2    fmt::{Debug, Pointer},
3    hash::Hash,
4    panic::{RefUnwindSafe, UnwindSafe},
5};
6
7use crate::{
8    WithAbi, WithSafety, abi,
9    abi::{Abi, AbiKey},
10    make_safe, make_unsafe,
11};
12
13ffi_opaque::opaque! {
14    /// A struct representing an opaque function.
15    pub struct OpaqueFn;
16}
17
18/// Type alias for a raw untyped function pointer.
19pub type UntypedFnPtr = *const OpaqueFn;
20
21macro_rules! fnptr_trait_body {
22    () => {
23        /// The argument types as a tuple.
24        type Args;
25
26        /// The return type.
27        type Output;
28
29        /// The function's arity (number of arguments).
30        const ARITY: usize;
31
32        /// Whether the function pointer is safe (fn) or unsafe (unsafe fn).
33        const IS_SAFE: bool;
34
35        /// Whether the function pointer uses an extern calling convention.
36        const IS_EXTERN: bool;
37
38        /// The ABI associated with this function pointer.
39        const ABI: Abi;
40
41        /// Returns the address of this function.
42        #[must_use]
43        fn addr(&self) -> usize {
44            self.as_ptr() as usize
45        }
46        /// Constructs an instance from an address.
47        ///
48        /// # Safety
49        /// This function is unsafe because it can not check if the argument points to a function
50        /// of the correct type.
51        #[must_use]
52        unsafe fn from_addr(addr: usize) -> Self {
53            unsafe { Self::from_ptr(addr as UntypedFnPtr) }
54        }
55
56        /// Returns a untyped function pointer for this function.
57        #[must_use]
58        fn as_ptr(&self) -> UntypedFnPtr;
59        /// Constructs an instance from an untyped function pointer.
60        ///
61        /// # Safety
62        /// This function is unsafe because it can not check if the argument points to a function
63        /// of the correct type.
64        #[must_use]
65        unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
66
67        /// Produces an unsafe version of this function pointer.
68        #[must_use]
69        fn as_unsafe(&self) -> make_unsafe!(Self) {
70            unsafe { FnPtr::from_ptr(self.as_ptr()) }
71        }
72
73        /// Produces a safe version of this function pointer.
74        ///
75        /// # Safety
76        /// Caller must ensure the underlying function is actually safe to call.
77        #[must_use]
78        unsafe fn as_safe(&self) -> make_safe!(Self) {
79            unsafe { FnPtr::from_ptr(self.as_ptr()) }
80        }
81
82        /// Produces a version of this function pointer with the given ABI.
83        ///
84        /// # Safety
85        /// Caller must ensure that the resulting ABI transformation is sound.
86        #[must_use]
87        unsafe fn with_abi<const ABI: AbiKey>(&self) -> <Self as WithAbi<ABI>>::F
88        where
89            Self: WithAbi<ABI>,
90        {
91            unsafe { FnPtr::from_ptr(self.as_ptr()) }
92        }
93    };
94}
95/// Marker trait for all function pointers.
96#[cfg(not(nightly_build))]
97pub trait FnPtr:
98    PartialEq
99    + Eq
100    + PartialOrd
101    + Ord
102    + Hash
103    + Pointer
104    + Debug
105    + Clone
106    + Copy
107    + Send
108    + Sync
109    + Unpin
110    + UnwindSafe
111    + RefUnwindSafe
112    + Sized
113    + 'static
114    + WithSafety<true>
115    + WithSafety<false>
116    + WithAbi<{ abi!("Rust") }>
117    + WithAbi<{ abi!("C") }>
118    + WithAbi<{ abi!("system") }>
119{
120    fnptr_trait_body!();
121}
122
123/// Marker trait for all function pointers.
124#[cfg(nightly_build)]
125pub trait FnPtr:
126    PartialEq
127    + Eq
128    + PartialOrd
129    + Ord
130    + Hash
131    + Pointer
132    + Debug
133    + Clone
134    + Copy
135    + Send
136    + Sync
137    + Unpin
138    + UnwindSafe
139    + RefUnwindSafe
140    + Sized
141    + 'static
142    + WithSafety<true>
143    + WithSafety<false>
144    + WithAbi<{ abi!("Rust") }>
145    + WithAbi<{ abi!("C") }>
146    + WithAbi<{ abi!("system") }>
147    + std::marker::FnPtr
148{
149    fnptr_trait_body!();
150}
151
152/// Marker trait for all *safe* function pointer types (`fn` / `extern fn`).
153pub trait SafeFnPtr: FnPtr {
154    /// Invokes the function pointed to with the given args.
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// # use fn_ptr::SafeFnPtr;
160    /// fn add(a: i32, b: i32) -> i32 { a + b }
161    ///
162    /// let f: fn(i32, i32) -> i32 = add;
163    /// let result = f.invoke((2, 3));
164    /// assert_eq!(result, 5);
165    /// ```
166    // NOTE: Can't use "call" due to fn_traits feature
167    fn invoke(&self, args: Self::Args) -> Self::Output;
168}
169
170/// Marker trait for all *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
171pub trait UnsafeFnPtr: FnPtr {
172    /// Invokes the function pointed to with the given args.
173    ///
174    /// # Safety
175    /// Calling this function pointer is unsafe because the function may have
176    /// invariants that must be manually upheld by the caller.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// # use fn_ptr::UnsafeFnPtr;
182    /// unsafe fn add(a: *const i32, b: *const i32) -> i32 { *a + *b }
183    ///
184    /// let f: unsafe fn(*const i32, *const i32) -> i32 = add;
185    /// let result = unsafe { f.invoke((&2, &3)) };
186    /// assert_eq!(result, 5);
187    /// ```
188    // NOTE: Can't use "call" due to fn_traits feature
189    unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
190}
191
192/// Marker trait implemented for function pointers of a specific ABI.
193///
194/// For example:
195/// - `HasAbi<Abi::C>` for `extern "C" fn(...)`
196/// - `HasAbi<Abi::Sysv64>` for `extern "sysv64" fn(...)`
197pub trait HasAbi<const ABI: AbiKey>: FnPtr {}
198
199/// Marker trait denoting the safety of a function pointer type.
200///
201/// For example:
202/// - `HasSafety<true>` for `extern "C" fn(...)`
203/// - `HasSafety<false>` for `unsafe fn(...)`
204pub trait HasSafety<const B: bool> {}
205impl<T: SafeFnPtr> HasSafety<true> for T {}
206impl<T: UnsafeFnPtr> HasSafety<false> for T {}