Thanks to visit codestin.com
Credit goes to lib.rs

8 releases (4 breaking)

0.5.0 Oct 13, 2019
0.4.0 Mar 4, 2019
0.3.2 Nov 28, 2017
0.3.0 Sep 5, 2017
0.1.0 Jan 31, 2017

#27 in FFI

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

8,777,493 downloads per month
Used in 12,144 crates (67 directly)

MIT/Apache

17KB
96 lines

foreign-types

CircleCI

Documentation

A framework for Rust wrappers over C APIs.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


lib.rs:

A framework for Rust wrappers over C APIs.

Ownership is as important in C as it is in Rust, but the semantics are often implicit. In particular, pointer-to-value is commonly used to pass C values both when transferring ownership or a borrow.

This crate provides a framework to define a Rust wrapper over these kinds of raw C APIs in a way that allows ownership semantics to be expressed in an ergonomic manner. The framework takes a dual-type approach similar to APIs in the standard library such as PathBuf/Path or String/ str. One type represents an owned value and references to the other represent borrowed values.

Examples

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...

The foreign_type! macro can generate this boilerplate for you:

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;
    }
}

If fn clone is specified, then it must take CType as an argument and return a copy of it as CType. It will be used to implement Clone, and if the std Cargo feature is enabled, ToOwned.

Say we then have a separate type in our C API that contains a FOO:

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;
    }
}

The documentation for the C library states that BAR_get_foo returns a reference into the BAR passed to it, which translates into a reference in Rust. It also says that we're allowed to modify the FOO, so we'll define a pair of accessor methods, one immutable and one mutable:

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())) }
    }
}

Dependencies

~185–610KB
~15K SLoC