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 模式

Download history 912037/week @ 2024-03-14 914833/week @ 2024-03-21 902776/week @ 2024-03-28 937330/week @ 2024-04-04 972688/week @ 2024-04-11 982902/week @ 2024-04-18 959739/week @ 2024-04-25 975383/week @ 2024-05-02 958991/week @ 2024-05-09 1002662/week @ 2024-05-16 983817/week @ 2024-05-23 1063349/week @ 2024-05-30 1017375/week @ 2024-06-06 1046442/week @ 2024-06-13 1004347/week @ 2024-06-20 853083/week @ 2024-06-27

4,126,858 每月下载量
8,994 个crate中使用 (59 直接使用)

MIT/Apache

17KB
96

foreign-types

CircleCI

文档

C APIs 的 Rust 包装框架。

许可

许可协议为以下之一:

任选其一。

贡献

除非你明确声明,否则任何提交给作品以包含在内的贡献,根据 Apache-2.0 许可证定义,应作为上述双重许可,不附加任何额外条款或条件。


lib.rs:

C APIs 的 Rust 包装框架。

C 语言与 Rust 一样重视所有权,但语义通常是隐含的。特别是,指针到值在传递所有权或借用时常用作传递 C 值。

此 crate 提供了一个框架,以定义一种方式,允许以方便的方式表达所有权语义,从而在这些原始 C API 上定义 Rust 包装。该框架采用类似于标准库中 API 的双类型方法,例如 PathBuf/PathString/ 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