Skip to main content

ffi

Attribute Macro ffi 

Source
#[ffi]
Expand description

Wrap an impl block with #[ffi(...)] to generate FFI functions for all methods in the impl block.

§Arguments

The impl-level ffi attribute accepts the following parameters:

  • mod_name: The name of the module to create to contain the FFI functions. Defaults to the name of the type being implemented, converted to lowercase. For example name = "vec3_mod".
  • visibility: The visibility of the module to create to contain the FFI functions. Defaults to pub. For example visibility = "pub(crate)".
  • self_ty: The self type to use for the receiver argument for all methods. Defaults to a mut pointer to the type being implemented. For example self_ty = "*mut std::ffi::c_void".
  • expect: If the method returns a Result, whether to call .expect on the result. Defaults to false. For example expect.
  • from_ptr: Whether to generate From<T> where T is the type specified in self_ty. Defaults to false. For example from_ptr. If not specified, a manual implementation must be provided.
  • from_any_ptr: Whether to generate From<*mut T>. Defaults to false. For example from_any_ptr. If not specified, a manual implementation must be provided.

For example, an impl-level attribute specifying that a public module named my_ffi_mod, containing FFI functions for all methods in the Vec3 impl block, should be generated, with the receiver type *mut std::ffi::c_void and that methods which return a Result should be .expect-ed and a From<*mut std::ffi::c_void> implementation should be generated, would look like:

#[ffi(mod_name = "my_ffi_mod", self_ty = "*mut std::ffi::c_void", expect, from_ptr)]

The method-level ffi attribute accepts the following parameters:

  • expect: If the method returns a Result, whether to call .expect on the result. Defaults to false. For example expect. If not specified on the impl level attribute, the module level attribute takes precedence.
  • visibility: The visibility of the generated FFI function. Defaults to pub. For example visibility = "pub(crate)".
  • name: The name of the generated FFI function. Defaults to the name of the method being implemented. For example name = "vec3_add".
  • arg: Can be specified multiple times. The arguments to the generated FFI function.

For example, a method-level attribute specifying that a public FFI function named vec3_add should be generated, which takes its receiver as the last argument and that methods which return a Result should be .expect-ed, would look like:

#[ffi(arg(), arg(), arg(), arg(self), expect, name = "vec3_add")]
fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }

The argument-level arg attribute accepts the following parameters:

  • self: Whether this argument needs to be converted to the receiver type. Defaults to false. For example self.
  • rest: Whether this argument is the rest of the arguments. Defaults to false. After rest is specified, no other arg attributes may be specified.
  • ty: The type to convert this argument to. Defaults to the type of the argument. For example ty = "i32". A valid From implementation must exist for this type.
  • rename: The name of the argument in the generated FFI function. Defaults to the name of the argument. For example rename = "x".

An empty arg() specifies only the position of an argument. In the following example, we specify that the FFI function should receive the first three non-receiver arguments, then the receiver argument.

#[ffi(arg(), arg(), arg(), arg(self))]
fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }

This is equivalent to:

#[ffi(arg(rest), arg(self))]
fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }

Likewise:

#[ffi(arg(self), arg(), arg(), arg())]
fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }

is equivalent to:

#[ffi(arg(self), arg(rest))]
fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }

§Example

The simple use case, where a callback we specify is called with user data we specify.

use ffi::ffi;

extern "C" fn run_callback(
    callback: extern "C" fn(*mut std::ffi::c_void, i32, i32, i32) -> i32,
    data: *mut std::ffi::c_void,
) -> i32 {
    callback(data, 1, 2, 3)
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Vec3 {
    x: i32,
    y: i32,
    z: i32,
}

#[ffi(from_ptr, self_ty = "*mut std::ffi::c_void")]
impl Vec3 {
    #[ffi(arg(self), arg(rest))]
    fn add(&mut self, x: i32, y: i32, z: i32) -> i32 {
        self.x += x;
        self.y += y;
        self.z += z;
        self.x + self.y + self.z
    }
}

fn main() {
    let mut v = Vec3 { x: 1, y: 2, z: 3 };

    run_callback(vec3::add, &mut v as *mut Vec3 as *mut _);

    assert_eq!(v, Vec3 { x: 2, y: 4, z: 6 })
}