Passing a C callback to Rust

Hello !
I am trying to make my Rust library interact with C, and I ran into an weird case.
I have the following rust code :

struct Caller<F: Fn()> {
    function: F,
}

impl<F: Fn()> Caller<F> {
    fn call(&self) {
        (self.function)()
    }
}

And my goal is to expose the Caller struct to C : but

  • This code fails to compile because extern "C" fn() does not implement Fn()
type Callback = extern "C" fn();

#[no_mangle]
extern "C" fn create_caller(function: Callback) -> *mut Caller<Callback> {
    Box::leak(Box::new(Caller { function }))
}
  • And this one warns me that Caller<impl Fn()> is not ffi-safe
type Callback = extern "C" fn();

#[no_mangle]
extern "C" fn create_caller(function: Callback) -> *mut Caller<impl Fn()> {
    Box::leak(Box::new(Caller {
        function: move || function(),
    }))
}

Is the second version correct, despite the warning? Or is there a third, better way to do ?

Why not use

type Callback = extern "C" fn();
struct Caller {
    function: Callback,
}

I don't think generics are needed?

Well Caller is a bit more complex in reality, but the main reason it that it is used by Rust code, and it might make sense to create it with a closure for example.
Basically I am trying to make a C interface out of some pre-existing Rust code, and Caller is a part of it.

Would something like this work?

The Caller here could be a different type from the Caller in your original code, and you can provide conversions between them.

This works like a charm, thanks !

1 Like

A while back I did a write up on passing closures to native code. It might help explain why @RustyYato's answer works and provide an alternative implementation without the double-indirection.

1 Like