An open API service indexing awesome lists of open source software.

https://github.com/aandreba/ffi-closure

Send and recevie closures through FFI
https://github.com/aandreba/ffi-closure

Last synced: 7 months ago
JSON representation

Send and recevie closures through FFI

Awesome Lists containing this project

README

          

# ffi-closure - Send and Receive closures through FFI

[![Crates.io Version](https://img.shields.io/crates/v/ffi-closure)
](https://crates.io/crates/ffi-closure)
[![docs.rs](https://img.shields.io/docsrs/ffi-closure)](https://docs.rs/ffi-closure/)

## Features

- Simple to use API
- Allows sending Rust functions & closures through FFI boundary
- `no-std` compatible
- Supports multiple calling conventions (defaults to C calling convention)
- Simplifies usage and interaction with FFI _closure-like_ functions
- Closures can have destructors
- Can specify closure's thread-safety level (None, `Send`, `Sync` or `Send + Sync`)

## Examples

**Export closure**

```rust
use ffi_closure::Closure;
use std::ffi::c_void;
# mod sys {
# use core::ffi::c_void;
# #[no_mangle]
# unsafe extern "C" fn some_lib_fn(f: unsafe extern "C" fn(i8, *mut c_void), user_data: *mut c_void) { f(-1, user_data) }
# }

extern "C" {
fn some_lib_fn(f: unsafe extern "C" fn(i8, *mut c_void), user_data: *mut c_void);
}

pub fn main() {
let weight = std::env::args().len() as i8;
let closure = Closure::::new(move |x| println!("{}", x * weight));

let (f, user_data): (unsafe extern "C" fn(i8, *mut c_void), *mut c_void) = closure.as_extern_parts();
unsafe {
some_lib_fn(f, user_data);
}
}

```

**Exported closure w/ system calling convention**

```rust
use ffi_closure::{Closure, cc::System};
use std::ffi::c_void;
# mod sys {
# use core::ffi::c_void;
# #[no_mangle]
# unsafe extern "C" fn some_lib_fn(f: unsafe extern "C" fn(i8, *mut c_void), user_data: *mut c_void) { f(-1, user_data) }
# }

extern "C" {
fn some_lib_fn(f: unsafe extern "system" fn(i8, *mut c_void), user_data: *mut c_void);
}

pub fn main() {
let weight = std::env::args().len() as i8;
let closure = Closure::::new(move |x| println!("{}", x * weight));

let (f, user_data): (unsafe extern "system" fn(i8, *mut c_void), *mut c_void) = closure.as_extern_parts();
unsafe {
some_lib_fn(f, user_data);
}
}
```

**Imported closure**

```rust
use ffi_closure::Closure;
use std::ffi::c_void;

#[no_mangle]
pub extern "C" fn some_lib_fn(
f: unsafe extern "C" fn(i8, *mut c_void),
user_data: *mut c_void,
) {
let mut f = unsafe { Closure::::from_extern(f, user_data, None) };
for i in 0..10 {
f(i);
}
}

```

**Imported, thread-safe closure**

```rust
use ffi_closure::{Closure};
use std::ffi::c_void;

#[no_mangle]
pub unsafe extern "C" fn some_lib_fn(
f: unsafe extern "C" fn(i8, *mut c_void),
user_data: *mut c_void,
) {
// SAFETY: Caller must ensure the passed function pointer and user data are thread-safe.
let mut f = unsafe { Closure::::from_extern(f, user_data, None) };

std::thread::spawn(move || {
for i in 0..10 {
f(i);
}
});
}

```

> **Note**\
> For `Closure` to implement `FnOnce` and `FnMut`, the 'nightly' feature must be enabled (and thus, the program must be built with nightly Rust).
> For a non-nightly version, use `Closure::call`