8 个版本 (4 个破坏性更新)
0.5.0 | 2019 年 10 月 13 日 |
---|---|
0.4.0 | 2019 年 3 月 4 日 |
0.3.2 | 2017 年 11 月 28 日 |
0.3.0 | 2017 年 9 月 5 日 |
0.1.0 | 2017 年 1 月 31 日 |
#553 in Rust 模式
4,126,858 每月下载量
在 8,994 个crate中使用 (59 直接使用)
17KB
96 行
foreign-types
C APIs 的 Rust 包装框架。
许可
许可协议为以下之一:
- Apache License,版本 2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非你明确声明,否则任何提交给作品以包含在内的贡献,根据 Apache-2.0 许可证定义,应作为上述双重许可,不附加任何额外条款或条件。
lib.rs
:
C APIs 的 Rust 包装框架。
C 语言与 Rust 一样重视所有权,但语义通常是隐含的。特别是,指针到值在传递所有权或借用时常用作传递 C 值。
此 crate 提供了一个框架,以定义一种方式,允许以方便的方式表达所有权语义,从而在这些原始 C API 上定义 Rust 包装。该框架采用类似于标准库中 API 的双类型方法,例如 PathBuf
/Path
或 String
/ str
。一种类型表示拥有的值,而引用到另一种类型的值表示借用值。
示例
use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
mod foo_sys {
pub enum FOO {}
extern {
pub fn FOO_free(foo: *mut FOO);
}
}
// The borrowed type is a newtype wrapper around an `Opaque` value.
//
// `FooRef` values never exist; we instead create references to `FooRef`s
// from raw C pointers.
pub struct FooRef(Opaque);
unsafe impl ForeignTypeRef for FooRef {
type CType = foo_sys::FOO;
}
// The owned type is simply a newtype wrapper around the raw C type.
//
// It dereferences to `FooRef`, so methods that do not require ownership
// should be defined there.
pub struct Foo(NonNull<foo_sys::FOO>);
unsafe impl Sync for FooRef {}
unsafe impl Send for FooRef {}
unsafe impl Sync for Foo {}
unsafe impl Send for Foo {}
impl Drop for Foo {
fn drop(&mut self) {
unsafe { foo_sys::FOO_free(self.as_ptr()) }
}
}
unsafe impl ForeignType for Foo {
type CType = foo_sys::FOO;
type Ref = FooRef;
unsafe fn from_ptr(ptr: *mut foo_sys::FOO) -> Foo {
Foo(NonNull::new_unchecked(ptr))
}
fn as_ptr(&self) -> *mut foo_sys::FOO {
self.0.as_ptr()
}
fn into_ptr(self) -> *mut foo_sys::FOO {
let inner = self.as_ptr();
::core::mem::forget(self);
inner
}
}
impl Deref for Foo {
type Target = FooRef;
fn deref(&self) -> &FooRef {
unsafe { FooRef::from_ptr(self.as_ptr()) }
}
}
impl DerefMut for Foo {
fn deref_mut(&mut self) -> &mut FooRef {
unsafe { FooRef::from_ptr_mut(self.as_ptr()) }
}
}
// add in Borrow, BorrowMut, AsRef, AsRefMut, Clone, ToOwned...
foreign_type!
宏可以为您生成此类样板代码
use foreign_types::foreign_type;
mod foo_sys {
pub enum FOO {}
extern {
pub fn FOO_free(foo: *mut FOO);
pub fn FOO_duplicate(foo: *mut FOO) -> *mut FOO; // optional
}
}
foreign_type! {
/// A Foo.
pub unsafe type Foo
: Sync + Send // optional
{
type CType = foo_sys::FOO;
fn drop = foo_sys::FOO_free;
fn clone = foo_sys::FOO_duplicate; // optional
}
/// A Foo with generic parameters.
pub unsafe type GenericFoo<T> {
type CType = foo_sys::FOO;
// This type is added as a `PhantomData` field to handle variance
// of the parameters. However, it has no impact on trait impls:
// `GenericFoo<T>` is always `Clone`, even if `T` is not.
type PhantomData = T;
fn drop = foo_sys::FOO_free;
fn clone = foo_sys::FOO_duplicate;
}
}
如果指定了 fn clone
,则它必须接受 CType
作为参数并返回其副本作为 CType
。它将用于实现 Clone
,如果启用 std
Cargo 功能,则还将实现 ToOwned
。
假设我们有一个包含 FOO
的单独的 C API 类型
mod foo_sys {
pub enum FOO {}
pub enum BAR {}
extern {
pub fn FOO_free(foo: *mut FOO);
pub fn BAR_free(bar: *mut BAR);
pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO;
}
}
C库的文档指出,BAR_get_foo
返回一个对传入的 BAR
的引用,这在Rust中对应于一个引用。它还说明我们可以修改 FOO
,因此我们将定义一对访问器方法,一个不可变和一个可变。
use foreign_types::{ForeignTypeRef, foreign_type};
mod foo_sys {
pub enum FOO {}
pub enum BAR {}
extern {
pub fn FOO_free(foo: *mut FOO);
pub fn BAR_free(bar: *mut BAR);
pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO;
}
}
foreign_type! {
/// A Foo.
pub unsafe type Foo: Sync + Send {
type CType = foo_sys::FOO;
fn drop = foo_sys::FOO_free;
}
/// A Bar.
pub unsafe type Bar: Sync + Send {
type CType = foo_sys::BAR;
fn drop = foo_sys::BAR_free;
}
}
impl BarRef {
fn foo(&self) -> &FooRef {
unsafe { FooRef::from_ptr(foo_sys::BAR_get_foo(self.as_ptr())) }
}
fn foo_mut(&mut self) -> &mut FooRef {
unsafe { FooRef::from_ptr_mut(foo_sys::BAR_get_foo(self.as_ptr())) }
}
}
依赖项
~285–740KB
~18K SLoC