ffi_closure/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(
4    feature = "nightly",
5    feature(unsize, fn_ptr_trait, unboxed_closures, fn_traits, tuple_trait)
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8
9use alloc::boxed::Box;
10use cc::{AsExtern, CallingConvention, IntoExtern, C};
11use core::{ffi::c_void, marker::PhantomData, mem::ManuallyDrop};
12use docfg::docfg;
13
14extern crate alloc;
15
16/// Calling conventions
17pub mod cc;
18
19/// A closure that can be sent through an FFI boundary.
20pub struct Closure<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention = C> {
21    f: T::Extern,
22    user_data: *mut c_void,
23    destructor: Option<Cc::Destructor>,
24    _phtm: PhantomData<T>,
25}
26
27impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> Closure<T, Cc> {
28    /// Creates a new `Closure` from a Rust closure.
29    ///
30    /// ## Example
31    /// ```
32    /// # use ffi_closure::Closure;
33    /// # use core::ffi::c_void;
34    /// let mut square = Closure::<dyn FnMut(u32) -> u32>::new(|x| x * x);
35    /// assert_eq!(square.call((3,)), 9);
36    /// ```
37    #[inline]
38    pub fn new<F: IntoExtern<T, Cc>>(f: F) -> Self {
39        return Box::new(f).into_extern();
40    }
41
42    /// Creates a new `Closure` from an external function pointer and user data.
43    ///
44    /// ## Example
45    /// ```
46    /// # use ffi_closure::Closure;
47    /// # use core::ffi::c_void;
48    /// unsafe extern "C" fn square(x: u32, _: *mut c_void) -> u32 {
49    ///     return x * x
50    /// }
51    ///
52    /// let mut square = unsafe { Closure::<dyn FnMut(u32) -> u32>::from_extern(square, core::ptr::null_mut(), None) };
53    /// assert_eq!(square.call((3,)), 9);
54    /// ```
55    #[inline]
56    pub unsafe fn from_extern(
57        f: T::Extern,
58        user_data: *mut c_void,
59        destructor: Option<Cc::Destructor>,
60    ) -> Self {
61        return Self {
62            f,
63            user_data,
64            destructor,
65            _phtm: PhantomData,
66        };
67    }
68
69    /// Returns the parts that form the closure, without droping it.
70    /// Caller is responsibnle for correct deinitialization of the extracted closure.
71    pub fn into_parts(self) -> (*mut c_void, T::Extern, Option<Cc::Destructor>) {
72        let this = ManuallyDrop::new(self);
73        return (this.user_data, this.f, this.destructor);
74    }
75
76    /// Returns `true` if this closure has a destructor, `false` otherwise
77    #[inline(always)]
78    pub fn has_destructor(&self) -> bool {
79        return self.destructor.is_some();
80    }
81
82    /// Returns the user data of this `Closure`
83    #[inline(always)]
84    pub fn user_data(&self) -> *mut c_void {
85        return self.user_data;
86    }
87
88    /// Returns the function pointer of this `Closure`
89    #[inline(always)]
90    pub fn fn_ptr(&self) -> T::Extern {
91        return self.f;
92    }
93
94    /// Returns the function pointer and user data of this `Closure`
95    ///
96    /// ## Example
97    /// ```
98    /// # use ffi_closure::Closure;
99    /// # use core::ffi::c_void;
100    /// let mut square = Closure::<dyn FnMut(u32) -> u32>::new(|x| x * x);
101    /// let (f, user_data): (unsafe extern "C" fn(u32, *mut c_void) -> u32, *mut c_void) = square.as_extern_parts();
102    /// unsafe { assert_eq!(f(3, user_data), 9) }
103    /// ```
104    #[inline(always)]
105    pub fn as_extern_parts(&self) -> (T::Extern, *mut c_void) {
106        return (self.fn_ptr(), self.user_data);
107    }
108
109    /// Calls the `Closure`'s function pointer with the provided arguments and it's user data
110    ///
111    /// ## Example
112    /// ```
113    /// # use ffi_closure::Closure;
114    /// # use core::ffi::c_void;
115    /// let mut square = Closure::<dyn FnMut(u32) -> u32>::new(|x| x * x);
116    /// assert_eq!(square.call((3,)), 9);
117    /// ```
118    #[inline(always)]
119    pub fn call(&mut self, args: T::Args) -> T::Output {
120        unsafe { T::call_mut(self.f, args, self.user_data) }
121    }
122}
123
124#[docfg(feature = "nightly")]
125impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> FnOnce<T::Args> for Closure<T, Cc>
126where
127    T::Args: core::marker::Tuple,
128{
129    type Output = <T as AsExtern<Cc>>::Output;
130
131    #[inline(always)]
132    extern "rust-call" fn call_once(self, args: T::Args) -> Self::Output {
133        unsafe { T::call_mut(self.f, args, self.user_data) }
134    }
135}
136
137#[docfg(feature = "nightly")]
138impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> FnMut<T::Args> for Closure<T, Cc>
139where
140    T::Args: core::marker::Tuple,
141{
142    #[inline(always)]
143    extern "rust-call" fn call_mut(&mut self, args: T::Args) -> Self::Output {
144        unsafe { T::call_mut(self.f, args, self.user_data) }
145    }
146}
147
148impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> Drop for Closure<T, Cc> {
149    #[inline]
150    fn drop(&mut self) {
151        if let Some(f) = self.destructor.take() {
152            unsafe { Cc::destroy(f, self.user_data) }
153        }
154    }
155}
156
157unsafe impl<T: ?Sized + AsExtern<Cc> + Send, Cc: CallingConvention> Send for Closure<T, Cc> {}
158unsafe impl<T: ?Sized + AsExtern<Cc> + Sync, Cc: CallingConvention> Sync for Closure<T, Cc> {}
159
160/// ```compile_fail
161/// fn thread_safety_fail() {
162///     let mut res = 0;
163///     let mut closure1 = Closure::<dyn Send + FnMut()>::new(|| res += 1);
164///     let mut closure2 = Closure::<dyn Send + FnMut()>::new(|| res += 1);
165///
166///     std::thread::spawn(move || closure1.call(()));
167///     closure2.call(());
168///
169///     println!("{res}")
170/// }
171/// ```
172///
173/// ```compile_fail
174/// fn lifetime_safety_fail() {
175///     let res = AtomicU32::new(0);
176///
177///     let mut closure = Closure::<dyn Send + FnMut()>::new(|| {
178///         res.fetch_add(1, Ordering::AcqRel);
179///     });
180///
181///     std::thread::spawn(move || closure.call(()));
182/// }
183/// ```
184#[doc(hidden)]
185mod compile_fail {}