This works, but means that for each call of the callback I have two dynamic function calls. Since the library I'm wrapping is pretty performance sensitive, I would like to somehow eliminate one of those calls.
This, of course, only works if I don't have any dynamic dispatch on the rust side. What I would love here is the option to "export" a generic function. What I mean by that: Have a generic function, and automatically export every monomorphisation of that function to C.
Then I could create a function like this:
extern "C" fn static_trampoline<F: FnMut()>(user_data: *mut c_void) {
let cb: &mut &mut F = unsafe { mem::transmute(user_data) };
cb()
}
And export a version of this function for every F in the whole program.
Sadly, as far as I can tell, this is impossible. What I would ask is if anyone has any other workarounds that would eliminate the dynamic dispatch but still result in a good user experience for the library.
Then at the top level, you would invoke the C function like this:
/// Add two numbers, passing the result to the provided closure for further
/// processing.
pub fn add_two_numbers<F>(a: i32, b: i32, on_result_calculated: F)
where
F: FnMut(i32),
{
unsafe {
let mut closure = on_result_calculated;
let cb = get_trampoline(&closure);
better_add_two_numbers(a, b, cb, &mut closure as *mut _ as *mut c_void);
}
}
Thanks for the quick responses, I totally missed that this is actually just possible
In the meantime I built a solution using exported functions within an impl block, but I guess I can simplify that now.
Cheers
(note: redrafted, because I accidentally responded to a specific comment, oops
Yeah, it's possible for concrete functions but can't be generalised because Rust doesn't have a way to be generic over functions with an arbitrary number of arguments ("variadic generics").