#pointers #opaque #cbindgen #no-std

no-std opaque-pointer

当使用FFI暴露Rust结构体时,用于处理不可见指针的泛型函数

7个版本

0.9.0 2024年5月6日
0.8.8 2023年4月22日
0.8.6 2021年12月9日
0.8.5 2021年5月12日
0.3.0 2020年9月13日

#74FFI

Download history 152/week @ 2024-04-20 264/week @ 2024-04-27 161/week @ 2024-05-04 23/week @ 2024-05-11 34/week @ 2024-05-18 24/week @ 2024-05-25 16/week @ 2024-06-01 19/week @ 2024-06-08 16/week @ 2024-06-15 59/week @ 2024-06-22 5/week @ 2024-06-29 15/week @ 2024-07-06 31/week @ 2024-07-13 47/week @ 2024-07-20 22/week @ 2024-07-27 26/week @ 2024-08-03

每月129次下载

Unlicense

18KB
186

无缝Rust FFI的不可见指针

利用泛型不可见指针实现Rust与C/C++的无缝FFI互操作性

Crates.io Crates.io Crates.io

概述

简化原始指针管理,将Rust结构体暴露为不可见指针,无缝实现Rust和C/C++函数之间的交互。此Crate通过cbindgen(使用parse.parse_deps = true)生成用于参数的不可见C/C++结构体。

要全面了解Rust与其他语言的互操作性,请参阅Jake Goulding的Rust FFI Omnibus对象部分

借出功能

通过激活lender功能,函数如own_back<T>()验证指针的有效性,确保其有效性。这意味着,它将由raw<T>()返回。

示例

创建FFI以从C或C++使用Rust的struct方法

struct Counter { value: u8 }

impl Counter {
    pub fn new() -> Self { Self { value: 0 } }
    pub fn add(&mut self, value: u8) { self.value += value }
    pub fn get(&self) -> u8 { self.value }
}

/// Ownership will NOT control the heap-allocated memory until own it back.
#[no_mangle]
pub extern fn counter_new(value: u8) -> *mut Counter {
    return opaque_pointer::raw(Counter::new())
            .expect("Error trying to lend a pointer");
}

/// Drop (free memory of) Rust's Counter object as usually.
#[no_mangle]
pub extern fn counter_free(counter: *mut Counter) {
    unsafe { opaque_pointer::own_back(counter) };
}

#[no_mangle]
pub extern fn counter_add(counter: *mut Counter, value: u8) -> bool {
    let counter = unsafe { opaque_pointer::mut_object(counter) };
    if counter.is_err() {
        return false;
    }
    let counter = counter.unwrap();
    counter.add(value);
    // Here will NOT be dropped, the pointer continues been valid.
    return true;
}

#[no_mangle]
pub extern fn counter_get(counter: *const Counter) -> u8  {
    let counter = unsafe { opaque_pointer::object(counter) };
    if counter.is_err() {
        return 0;
    }
    let counter = counter.unwrap();
    return counter.get();
    // Here will NOT be dropped, the pointer continues been valid.
}

上一个示例在运行测试时进行编译。如果您有该代码的错误,请打开一个issue

功能

  • std:默认激活,对于c类型FFI是必需的。
  • alloc:如果没有std编译则需要。
  • c-types:C类型的FFI,需要std功能。

FFI函数中的panic & unwind

此创建返回结果以避免指针为空时的恐慌,如果您的FFI需要检查恐慌,请查看以下链接。

请参阅gtk-rs问题#78中的评论,以获取良好的简历示例。

目前,任何跨extern "C"函数的 unwind 都是未定义的行为(UB),即使这些函数碰巧是用 Rust 实现的也是如此。这是该工作组正在努力解决的问题之一。例如,这添加了对extern "C-unwind" ABI的支持,该ABI明确允许unwind(并且据我所知,通过extern "C"进行unwind会导致程序异常终止,就像应该那样)。

以及Rust的 pull request #76570

另请参阅Rust问题#58794中的评论Rust问题#58760

在此PR中,将默认值更改为extern函数中的默认终止。这是跟踪#[unwind(allowed)](和#[unwind(abort)])属性的稳定化。

另请参阅Rust pull request #55982

此PR更改了生成代码的行为,使其默认为sound。如果extern fn发生unwind(通过panic进行)则程序立即终止。换句话说,任何extern fn都不能unwind。

以及Rust问题#52652

这个UB在任何后续的发布说明书中都没有提及。

依赖项

约90KB