[−][src]Crate foreign_types
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())) } } }
Macros
foreign_type | A macro to easily define wrappers for foreign types. |
Structs
Opaque | An opaque type used to define |
Traits
ForeignType | A type implemented by wrappers over foreign types. |
ForeignTypeRef | A trait implemented by types which reference borrowed foreign types. |