#closures #send-receive #send-sync #abi #c

no-std ffi-closure

通过FFI发送和接收闭包

2个稳定版本

1.1.0 2024年5月12日
1.0.0 2024年2月24日

#93 in FFI

MIT 许可证

18KB
270

ffi-closure - 通过FFI发送和接收闭包

Crates.io Version docs.rs

特性

  • 简单的API
  • 允许通过FFI边界发送Rust函数和闭包
  • no-std 兼容
  • 支持多种调用约定(默认为C调用约定)
  • 简化了与FFI 闭包样 函数的交互
  • 闭包可以有析构函数
  • 可以指定闭包的线程安全级别(None,SendSyncSend + Sync

示例

导出闭包

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::<dyn FnMut(i8)>::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);
    }
}

具有系统调用约定的导出闭包

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::<dyn FnMut(i8), System>::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);
    }
}

导入闭包

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::<dyn FnMut(i8)>::from_extern(f, user_data, None) };
    for i in 0..10 {
        f(i);
    }
}

线程安全的导入闭包

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::<dyn Send + FnMut(i8)>::from_extern(f, user_data, None) };

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

注意
为了使Closure实现FnOnceFnMut,必须启用'nightly'功能(因此,程序必须使用nightly Rust构建)。对于非nightly版本,请使用Closure::call

依赖关系

~1.5MB
~35K SLoC