How to pass pass a closure or Fn as an extern C callback without user argument

Hello,

I've made some research about how to pass a closure or a Fn to a C function as a callback.

I've mostly learnt that it's unfortunately not that simple. But it can be done only if the callbacks accepts a user defined data, from which one can pass the Fn as an argument / pointer to the callback.

If the callback doesn't accept user defined data, only static functions will work.

In my case I am lucky to have the callback accepting a user defined data that can be passed to the function.

But, out of curiosity, how would one write something like that:

// Callback doesn't allow any user defined data
pub type Callback = unsafe extern "c" fn(<some arguments>);

unsafe extern "c" set_callback(callback: *mut Callback);

// especially this part
fn set_my_callback(callback: ???) {
    unsafe { set_callback(callback) }; /// ??
}

Hoping I was clear enough.

Thank you very much in advance for any help

callbacks without a user provided context argument (directly or indirectly) must be stateless (unless you use global or thread local variables, but that's a different problem), in rust, you can only use function pointers and capture-less closures, you cannot use closures that captures states.

there are workaronds using so-called thunks, which requires dynamically generating machine code, but you need some form of dynamic assembler or JIT engine, and it's not always allowed on all operating systems.

examples of low level libraries and ffi bindings to craft your own thunks are dynasm, libffi, etc, there are also higher level, easy to use libraries, such as closure-ffi

1 Like

A Fn closure is essentially a function with some user-defined data (the data it closes over). If you can't pass the user-defined data then you can't use Fn and must instead take a plain fn that can't capture data.

1 Like

Thank you for your time.

So I suppose that the only way is to use one of the crates you suggested.

Thank you for your time.

So if unerstand well one of the main problem / difference a closure and plain fn is the fact that the closure will capture it's environment ?

I'm still not really sure how it's a problem ?

In order to call a closure, two pieces of data are needed, not one: a pointer to the machine code for the processor to execute, and a pointer to the captured data for that machine code to operate on.

1 Like

Oh okay thank you I think I understand.

I think you're trying to say that the closure requires two informations, while the C callback only requires one: the address.

Yes, and there needs to be some place to put the second.

Thank you now I understand.