1*e05fbacdSPaolo Bonzini // SPDX-License-Identifier: MIT 2*e05fbacdSPaolo Bonzini 3*e05fbacdSPaolo Bonzini //! Utility functions to deal with callbacks from C to Rust. 4*e05fbacdSPaolo Bonzini 5*e05fbacdSPaolo Bonzini use std::{mem, ptr::NonNull}; 6*e05fbacdSPaolo Bonzini 7*e05fbacdSPaolo Bonzini /// Trait for functions (types implementing [`Fn`]) that can be used as 8*e05fbacdSPaolo Bonzini /// callbacks. These include both zero-capture closures and function pointers. 9*e05fbacdSPaolo Bonzini /// 10*e05fbacdSPaolo Bonzini /// In Rust, calling a function through the `Fn` trait normally requires a 11*e05fbacdSPaolo Bonzini /// `self` parameter, even though for zero-sized functions (including function 12*e05fbacdSPaolo Bonzini /// pointers) the type itself contains all necessary information to call the 13*e05fbacdSPaolo Bonzini /// function. This trait provides a `call` function that doesn't require `self`, 14*e05fbacdSPaolo Bonzini /// allowing zero-sized functions to be called using only their type. 15*e05fbacdSPaolo Bonzini /// 16*e05fbacdSPaolo Bonzini /// This enables zero-sized functions to be passed entirely through generic 17*e05fbacdSPaolo Bonzini /// parameters and resolved at compile-time. A typical use is a function 18*e05fbacdSPaolo Bonzini /// receiving an unused parameter of generic type `F` and calling it via 19*e05fbacdSPaolo Bonzini /// `F::call` or passing it to another function via `func::<F>`. 20*e05fbacdSPaolo Bonzini /// 21*e05fbacdSPaolo Bonzini /// QEMU uses this trick to create wrappers to C callbacks. The wrappers 22*e05fbacdSPaolo Bonzini /// are needed to convert an opaque `*mut c_void` into a Rust reference, 23*e05fbacdSPaolo Bonzini /// but they only have a single opaque that they can use. The `FnCall` 24*e05fbacdSPaolo Bonzini /// trait makes it possible to use that opaque for `self` or any other 25*e05fbacdSPaolo Bonzini /// reference: 26*e05fbacdSPaolo Bonzini /// 27*e05fbacdSPaolo Bonzini /// ```ignore 28*e05fbacdSPaolo Bonzini /// // The compiler creates a new `rust_bh_cb` wrapper for each function 29*e05fbacdSPaolo Bonzini /// // passed to `qemu_bh_schedule_oneshot` below. 30*e05fbacdSPaolo Bonzini /// unsafe extern "C" fn rust_bh_cb<T, F: for<'a> FnCall<(&'a T,)>>( 31*e05fbacdSPaolo Bonzini /// opaque: *mut c_void, 32*e05fbacdSPaolo Bonzini /// ) { 33*e05fbacdSPaolo Bonzini /// // SAFETY: the opaque was passed as a reference to `T`. 34*e05fbacdSPaolo Bonzini /// F::call((unsafe { &*(opaque.cast::<T>()) }, )) 35*e05fbacdSPaolo Bonzini /// } 36*e05fbacdSPaolo Bonzini /// 37*e05fbacdSPaolo Bonzini /// // The `_f` parameter is unused but it helps the compiler build the appropriate `F`. 38*e05fbacdSPaolo Bonzini /// // Using a reference allows usage in const context. 39*e05fbacdSPaolo Bonzini /// fn qemu_bh_schedule_oneshot<T, F: for<'a> FnCall<(&'a T,)>>(_f: &F, opaque: &T) { 40*e05fbacdSPaolo Bonzini /// let cb: unsafe extern "C" fn(*mut c_void) = rust_bh_cb::<T, F>; 41*e05fbacdSPaolo Bonzini /// unsafe { 42*e05fbacdSPaolo Bonzini /// bindings::qemu_bh_schedule_oneshot(cb, opaque as *const T as *const c_void as *mut c_void) 43*e05fbacdSPaolo Bonzini /// } 44*e05fbacdSPaolo Bonzini /// } 45*e05fbacdSPaolo Bonzini /// ``` 46*e05fbacdSPaolo Bonzini /// 47*e05fbacdSPaolo Bonzini /// Each wrapper is a separate instance of `rust_bh_cb` and is therefore 48*e05fbacdSPaolo Bonzini /// compiled to a separate function ("monomorphization"). If you wanted 49*e05fbacdSPaolo Bonzini /// to pass `self` as the opaque value, the generic parameters would be 50*e05fbacdSPaolo Bonzini /// `rust_bh_cb::<Self, F>`. 51*e05fbacdSPaolo Bonzini /// 52*e05fbacdSPaolo Bonzini /// `Args` is a tuple type whose types are the arguments of the function, 53*e05fbacdSPaolo Bonzini /// while `R` is the returned type. 54*e05fbacdSPaolo Bonzini /// 55*e05fbacdSPaolo Bonzini /// # Examples 56*e05fbacdSPaolo Bonzini /// 57*e05fbacdSPaolo Bonzini /// ``` 58*e05fbacdSPaolo Bonzini /// # use qemu_api::callbacks::FnCall; 59*e05fbacdSPaolo Bonzini /// fn call_it<F: for<'a> FnCall<(&'a str,), String>>(_f: &F, s: &str) -> String { 60*e05fbacdSPaolo Bonzini /// F::call((s,)) 61*e05fbacdSPaolo Bonzini /// } 62*e05fbacdSPaolo Bonzini /// 63*e05fbacdSPaolo Bonzini /// let s: String = call_it(&str::to_owned, "hello world"); 64*e05fbacdSPaolo Bonzini /// assert_eq!(s, "hello world"); 65*e05fbacdSPaolo Bonzini /// ``` 66*e05fbacdSPaolo Bonzini /// 67*e05fbacdSPaolo Bonzini /// Note that the compiler will produce a different version of `call_it` for 68*e05fbacdSPaolo Bonzini /// each function that is passed to it. Therefore the argument is not really 69*e05fbacdSPaolo Bonzini /// used, except to decide what is `F` and what `F::call` does. 70*e05fbacdSPaolo Bonzini /// 71*e05fbacdSPaolo Bonzini /// Attempting to pass a non-zero-sized closure causes a compile-time failure: 72*e05fbacdSPaolo Bonzini /// 73*e05fbacdSPaolo Bonzini /// ```compile_fail 74*e05fbacdSPaolo Bonzini /// # use qemu_api::callbacks::FnCall; 75*e05fbacdSPaolo Bonzini /// # fn call_it<'a, F: FnCall<(&'a str,), String>>(_f: &F, s: &'a str) -> String { 76*e05fbacdSPaolo Bonzini /// # F::call((s,)) 77*e05fbacdSPaolo Bonzini /// # } 78*e05fbacdSPaolo Bonzini /// let x: &'static str = "goodbye world"; 79*e05fbacdSPaolo Bonzini /// call_it(&move |_| String::from(x), "hello workd"); 80*e05fbacdSPaolo Bonzini /// ``` 81*e05fbacdSPaolo Bonzini /// 82*e05fbacdSPaolo Bonzini /// # Safety 83*e05fbacdSPaolo Bonzini /// 84*e05fbacdSPaolo Bonzini /// Because `Self` is a zero-sized type, all instances of the type are 85*e05fbacdSPaolo Bonzini /// equivalent. However, in addition to this, `Self` must have no invariants 86*e05fbacdSPaolo Bonzini /// that could be violated by creating a reference to it. 87*e05fbacdSPaolo Bonzini /// 88*e05fbacdSPaolo Bonzini /// This is always true for zero-capture closures and function pointers, as long 89*e05fbacdSPaolo Bonzini /// as the code is able to name the function in the first place. 90*e05fbacdSPaolo Bonzini pub unsafe trait FnCall<Args, R = ()>: 'static + Sync + Sized { 91*e05fbacdSPaolo Bonzini /// Referring to this internal constant asserts that the `Self` type is 92*e05fbacdSPaolo Bonzini /// zero-sized. Can be replaced by an inline const expression in 93*e05fbacdSPaolo Bonzini /// Rust 1.79.0+. 94*e05fbacdSPaolo Bonzini const ASSERT_ZERO_SIZED: () = { assert!(mem::size_of::<Self>() == 0) }; 95*e05fbacdSPaolo Bonzini 96*e05fbacdSPaolo Bonzini /// Call the function with the arguments in args. 97*e05fbacdSPaolo Bonzini fn call(a: Args) -> R; 98*e05fbacdSPaolo Bonzini } 99*e05fbacdSPaolo Bonzini 100*e05fbacdSPaolo Bonzini macro_rules! impl_call { 101*e05fbacdSPaolo Bonzini ($($args:ident,)* ) => ( 102*e05fbacdSPaolo Bonzini // SAFETY: because each function is treated as a separate type, 103*e05fbacdSPaolo Bonzini // accessing `FnCall` is only possible in code that would be 104*e05fbacdSPaolo Bonzini // allowed to call the function. 105*e05fbacdSPaolo Bonzini unsafe impl<F, $($args,)* R> FnCall<($($args,)*), R> for F 106*e05fbacdSPaolo Bonzini where 107*e05fbacdSPaolo Bonzini F: 'static + Sync + Sized + Fn($($args, )*) -> R, 108*e05fbacdSPaolo Bonzini { 109*e05fbacdSPaolo Bonzini #[inline(always)] 110*e05fbacdSPaolo Bonzini fn call(a: ($($args,)*)) -> R { 111*e05fbacdSPaolo Bonzini let _: () = Self::ASSERT_ZERO_SIZED; 112*e05fbacdSPaolo Bonzini 113*e05fbacdSPaolo Bonzini // SAFETY: the safety of this method is the condition for implementing 114*e05fbacdSPaolo Bonzini // `FnCall`. As to the `NonNull` idiom to create a zero-sized type, 115*e05fbacdSPaolo Bonzini // see https://github.com/rust-lang/libs-team/issues/292. 116*e05fbacdSPaolo Bonzini let f: &'static F = unsafe { &*NonNull::<Self>::dangling().as_ptr() }; 117*e05fbacdSPaolo Bonzini let ($($args,)*) = a; 118*e05fbacdSPaolo Bonzini f($($args,)*) 119*e05fbacdSPaolo Bonzini } 120*e05fbacdSPaolo Bonzini } 121*e05fbacdSPaolo Bonzini ) 122*e05fbacdSPaolo Bonzini } 123*e05fbacdSPaolo Bonzini 124*e05fbacdSPaolo Bonzini impl_call!(_1, _2, _3, _4, _5,); 125*e05fbacdSPaolo Bonzini impl_call!(_1, _2, _3, _4,); 126*e05fbacdSPaolo Bonzini impl_call!(_1, _2, _3,); 127*e05fbacdSPaolo Bonzini impl_call!(_1, _2,); 128*e05fbacdSPaolo Bonzini impl_call!(_1,); 129*e05fbacdSPaolo Bonzini impl_call!(); 130*e05fbacdSPaolo Bonzini 131*e05fbacdSPaolo Bonzini #[cfg(test)] 132*e05fbacdSPaolo Bonzini mod tests { 133*e05fbacdSPaolo Bonzini use super::*; 134*e05fbacdSPaolo Bonzini 135*e05fbacdSPaolo Bonzini // The `_f` parameter is unused but it helps the compiler infer `F`. 136*e05fbacdSPaolo Bonzini fn do_test_call<'a, F: FnCall<(&'a str,), String>>(_f: &F) -> String { 137*e05fbacdSPaolo Bonzini F::call(("hello world",)) 138*e05fbacdSPaolo Bonzini } 139*e05fbacdSPaolo Bonzini 140*e05fbacdSPaolo Bonzini #[test] 141*e05fbacdSPaolo Bonzini fn test_call() { 142*e05fbacdSPaolo Bonzini assert_eq!(do_test_call(&str::to_owned), "hello world") 143*e05fbacdSPaolo Bonzini } 144*e05fbacdSPaolo Bonzini } 145