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 {}