Module interoptopus::patterns::callbacks[][src]

Expand description

Useful when extern "C" fn() delegate types give compile errors.

Example

If you want to accept user-provided callbacks or “delegates”:

 use interoptopus::{ffi_function, callback};
 use interoptopus::patterns::slice::FFISlice;

 callback!(CallbackSlice(x: FFISlice<u8>) -> u8);

 #[ffi_function]
 pub extern "C" fn my_function(callback: CallbackSlice) {
     callback.call(FFISlice::empty());
 }

Backends supporting this pattern might generate the equivalent to the following pseudo-code:

public delegate uint CallbackSlice(Sliceu8 x0);

void my_function(CallbackSlice callback);

Backends not supporting this pattern, and C FFI, will see the equivalent of the following C code:

typedef void (*fptr_fn_Sliceu8)(my_library_slicemutu8 x0);

void my_function(fptr_fn_Sliceu8 callback);

Code Generation

The macro callback enables two use cases:

  • On the Rust side it will generate a new function-pointer type with better compatibility with respect to lifetimes in signatures, and accepting an unlimited number of args.
  • On the FFI side a properly named callback (delegate, function pointer …) type can be produced (e.g., MyCallback), instead of one where it’s name is just a generic concatenation of all used parameters (e.g., InteropDelegate_fn_i32_i32).

Background

Due to how we generate FFI metadata and how Rust traits work there are some types which don’t work nicely with Interoptopus: function pointers. Practically speaking, the following code should work:

use interoptopus::ffi_function;
use interoptopus::patterns::slice::FFISlice;

pub type CallbackSlice = extern "C" fn(FFISlice<u8>);

#[ffi_function]
pub extern "C" fn my_function(callback: CallbackSlice) {
    callback(FFISlice::empty());
}

The intention is to provide a FFI function my_function, accepting a callback, which in turn accepts an FFISlice<'a, u8>. Although this is valid FFI code to write, a compile error is returned, which may look like this:

error: implementation of `CTypeInfo` is not general enough
   [...]
   = note: ...`CTypeInfo` would have to be implemented for the type `for<'r> extern "C" fn(FFISlice<'r, u8>)`
   = note: ...but `CTypeInfo` is actually implemented for the type `extern "C" fn(FFISlice<'0, u8>)`, for some specific lifetime `'0`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

The reasons for this are somewhat technical, but it boils down to us being unable to generally implement CTypeInfo for all types you may want to use; FFISlice here being one of them. To fix this, you can replace pub type CallbackSlice = ... with a callback! call which should generate a helper type that works.

Structs

Internal helper naming a generated callback type wrapper.