1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2018年2月25日 |
---|
#742 在 #ffi
9KB
65 行
一个针对 Rust 的可安全展开的 ffi 包装器生成器
更多详情请参阅文档。
许可证
许可协议为以下之一
- Apache 许可证2.0版(LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT 许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)任选其一。
贡献
除非你明确表示,否则根据 Apache-2.0 许可证定义的,你有意提交的任何贡献,都应按照上述方式双许可,不附加任何额外条款或条件。
lib.rs
:
Easy-FFI:一个 FFI 辅助宏的帮助宏
这个包试图使编写可安全展开的 C API 的过程更加人性化。
这个包的功能
- 防止跨 FFI 边界展开
- 允许使用通常的 Rust 错误处理习惯用法
这个包的功能 不 包括
- 防止你取消引用无效指针
- 防止内存泄露
- 对你 FFI 函数的参数或返回值的任何类型验证
示例
没有 easy_ffi
fn thing_that_could_fail_or_panic() -> Result<i32, &'static str> {
// Do stuff...
}
#[no_mangle]
pub extern "C" fn my_ffi_function(i: i32) -> i32 {
// Unwinding over the FFI boundary is UB, so we need to catch panics
let panic_result: Result<i32, _> = ::std::panic::catch_unwind(move || {
let result_one = thing_that_could_fail_or_panic();
// We need to match on this result to handle the possible Result::Err
// and convert it to a senssible ffi representation.
match result_one {
Ok(actual) => return actual,
Err(e) => {
println!("Oops! {:?}", e);
return -1;
}
}
});
// Then, we need to match on the catch_unwind result again like we did for the Result::Err
match panic_result {
Ok(actual) => return actual,
Err(_e) => {
println!("unexpected panic!");
return -1;
}
}
}
仅使用 rust std,任何可能引发恐慌的东西都需要用 catch_unwind
包装来防止进入 C。另外,由于 FFI 函数不会返回 Rust 的 Result<T, E>
,你无法使用 try!
或 ?
进行错误处理。
使用 easy_ffi
fn thing_that_could_fail_or_panic() -> Result<i32, &'static str> {
// Do stuff...
}
// This defines a new macro that will be used to wrap a more "rusty"
// version of our ffi function.
easy_ffi!(my_ffi_fn =>
// Now we define a handler for each of the error cases: A `Result::Err` and
// a caught panic. `Result::Err` comes first:
|err| {
println!("{}", err);
// The handler still needs to return the actual type that the C api expects,
// so we're going to do so here:
-1
}
// Next, the panic. This will have the type `Box<Any + Send + 'static>`. See
// `::std::panic::catch_unwind` for more details.
|panic_val| {
match panic_val.downcast_ref::<&'static str>() {
Some(s) => println!("panic: {}", s),
None => println!("unknown panic!"),
}
// As with the error handler, the panic handler also needs to return
// the real ffi return type.
-1
}
);
// Using the new macro that `easy_ffi!` created for us, we can write our
// function just like any Rust function that returns a `Result`. This will
// automatically be wrapped in a `catch_unwind`, and error handling will be
// left to the "handler" that was defined in the call to `easy_ffi`.
my_ffi_fn!(
/// You can put doc comments here!
///
/// This should generate a function with the signature `fn(i32) -> i32`,
/// with all of the necessary `pub`, `#[no_mangle]`, `extern "C"`, etc.
fn foo(i: i32) -> Result<i32, &'static str> {
thing_that_could_fail_or_panic()
}
);