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