1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
use std::ffi::c_void; /// Splits a closure into its data part and its code part, allowing it to be /// used as a callback by FFI code. /// /// # Examples /// /// ```rust /// use std::ffi::c_void; /// /// let mut total = 0; /// /// // let's define a closure which will update a total and return its new value /// let mut some_closure = |n: usize| { total += n; total }; /// /// // the callback the C function is expecting /// type Callback = unsafe extern "C" fn(*mut c_void, usize) -> usize; /// /// // pretend this is some C function which will periodically call a callback, /// // passing along a user-provided pointer for state. /// unsafe fn some_c_function(max_value: usize, cb: Callback, user_data: *mut c_void) { /// for i in 0..max_value { /// let got = cb(user_data, i); /// println!("iteration: {}, total: {}", i, got); /// } /// } /// /// unsafe { /// // split the closure into its state section and the code section /// let (state, callback) = ffi_helpers::split_closure(&mut some_closure); /// /// // then pass it to the C function /// some_c_function(42, callback, state); /// } /// /// assert_eq!(total, (0..42).sum()); /// ``` /// /// # Safety /// /// The returned function can only be called with the returned pointer, or a /// pointer to another `C` closure. pub unsafe fn split_closure<C, Args, Ret>( closure: &mut C, ) -> (*mut c_void, C::Trampoline) where C: Split<Args, Ret>, { (closure as *mut C as *mut c_void, C::trampoline()) } /// A helper trait used by [`split_closure()`] to get a trampoline function /// which will invoke the closure. /// /// This trait is automatically implemented for any `FnMut()` callable, you /// shouldn't implement it yourself. pub trait Split<Args, Ret> { type Trampoline; fn trampoline() -> Self::Trampoline; } macro_rules! impl_split { ($( $outer:ident ),* ; $( $inner:ident ),*) => { impl<Func, Ret, $($outer),*> Split<($( $outer, )*), Ret> for Func where Func: FnMut($($outer),*) -> Ret, { type Trampoline = unsafe extern "C" fn(*mut c_void, $($outer),*) -> Ret; fn trampoline() -> Self::Trampoline { // declare a trampoline function which will turn our pointer // back into an `F` and invoke it // Note: we're deliberately using `$inner` to generate an ident // for the argument #[allow(non_snake_case)] unsafe extern "C" fn trampoline<T, Ret_, $( $inner ),*>(ptr: *mut c_void, $($inner: $inner),*) -> Ret_ where T: FnMut($($inner),*) -> Ret_, { debug_assert!(!ptr.is_null()); let callback: &mut T = &mut *(ptr as *mut T); callback($($inner),*) } trampoline::<Func, Ret, $($outer,)*> } } }; } impl_split!(;); impl_split!(A; A); impl_split!(A, B; A, B); impl_split!(A, B, C; A, B, C); impl_split!(A, B, C, D; A, B, C, D); impl_split!(A, B, C, D, E; A, B, C, D, E); impl_split!(A, B, C, D, E, F; A, B, C, D, E, F); impl_split!(A, B, C, D, E, F, G; A, B, C, D, E, F, G); impl_split!(A, B, C, D, E, F, G, H; A, B, C, D, E, F, G, H); impl_split!(A, B, C, D, E, F, G, H, I; A, B, C, D, E, F, G, H, I); impl_split!(A, B, C, D, E, F, G, H, I, K; A, B, C, D, E, F, G, H, I, K); impl_split!(A, B, C, D, E, F, G, H, I, K, L; A, B, C, D, E, F, G, H, I, K, L); impl_split!(A, B, C, D, E, F, G, H, I, K, L, M; A, B, C, D, E, F, G, H, I, K, L, M); impl_split!(A, B, C, D, E, F, G, H, I, K, L, M, N; A, B, C, D, E, F, G, H, I, K, L, M, N); impl_split!(A, B, C, D, E, F, G, H, I, K, L, M, N, O; A, B, C, D, E, F, G, H, I, K, L, M, N, O);