foreign_types/
lib.rs

1//! A framework for Rust wrappers over C APIs.
2//!
3//! Ownership is as important in C as it is in Rust, but the semantics are often implicit. In
4//! particular, pointer-to-value is commonly used to pass C values both when transferring ownership
5//! or a borrow.
6//!
7//! This crate provides a framework to define a Rust wrapper over these kinds of raw C APIs in a way
8//! that allows ownership semantics to be expressed in an ergonomic manner. The framework takes a
9//! dual-type approach similar to APIs in the standard library such as `PathBuf`/`Path` or `String`/
10//! `str`. One type represents an owned value and references to the other represent borrowed
11//! values.
12//!
13//! # Examples
14//!
15//! ```
16//! use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
17//! use std::ops::{Deref, DerefMut};
18//!
19//! mod foo_sys {
20//!     pub enum FOO {}
21//!
22//!     extern {
23//!         pub fn FOO_free(foo: *mut FOO);
24//!     }
25//! }
26//!
27//! // The borrowed type is a newtype wrapper around an `Opaque` value.
28//! //
29//! // `FooRef` values never exist; we instead create references to `FooRef`s
30//! // from raw C pointers.
31//! pub struct FooRef(Opaque);
32//!
33//! impl ForeignTypeRef for FooRef {
34//!     type CType = foo_sys::FOO;
35//! }
36//!
37//! // The owned type is simply a newtype wrapper around the raw C type.
38//! //
39//! // It dereferences to `FooRef`, so methods that do not require ownership
40//! // should be defined there.
41//! pub struct Foo(*mut foo_sys::FOO);
42//!
43//! impl Drop for Foo {
44//!     fn drop(&mut self) {
45//!         unsafe { foo_sys::FOO_free(self.0) }
46//!     }
47//! }
48//!
49//! impl ForeignType for Foo {
50//!     type CType = foo_sys::FOO;
51//!     type Ref = FooRef;
52//!
53//!     unsafe fn from_ptr(ptr: *mut foo_sys::FOO) -> Foo {
54//!         Foo(ptr)
55//!     }
56//!
57//!     fn as_ptr(&self) -> *mut foo_sys::FOO {
58//!         self.0
59//!     }
60//! }
61//!
62//! impl Deref for Foo {
63//!     type Target = FooRef;
64//!
65//!     fn deref(&self) -> &FooRef {
66//!         unsafe { FooRef::from_ptr(self.0) }
67//!     }
68//! }
69//!
70//! impl DerefMut for Foo {
71//!     fn deref_mut(&mut self) -> &mut FooRef {
72//!         unsafe { FooRef::from_ptr_mut(self.0) }
73//!     }
74//! }
75//! ```
76//!
77//! The `foreign_type!` macro can generate this boilerplate for you:
78//!
79//! ```
80//! #[macro_use]
81//! extern crate foreign_types;
82//!
83//! mod foo_sys {
84//!     pub enum FOO {}
85//!
86//!     extern {
87//!         pub fn FOO_free(foo: *mut FOO);
88//!         pub fn FOO_duplicate(foo: *mut FOO) -> *mut FOO; // Optional
89//!     }
90//! }
91//!
92//! foreign_type! {
93//!     type CType = foo_sys::FOO;
94//!     fn drop = foo_sys::FOO_free;
95//!     fn clone = foo_sys::FOO_duplicate; // Optional
96//!     /// A Foo.
97//!     pub struct Foo;
98//!     /// A borrowed Foo.
99//!     pub struct FooRef;
100//! }
101//!
102//! # fn main() {}
103//! ```
104//!
105//! If `fn clone` is specified, then it must take `CType` as an argument and return a copy of it as `CType`.
106//! It will be used to implement `ToOwned` and `Clone`.
107//!
108//! `#[derive(…)] is permitted before the lines with `pub struct`.
109//! `#[doc(hidden)]` before the `type CType` line will hide the `foreign_type!` implementations from documentation.
110//!
111//! Say we then have a separate type in our C API that contains a `FOO`:
112//!
113//! ```
114//! mod foo_sys {
115//!     pub enum FOO {}
116//!     pub enum BAR {}
117//!
118//!     extern {
119//!         pub fn FOO_free(foo: *mut FOO);
120//!         pub fn BAR_free(bar: *mut BAR);
121//!         pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO;
122//!     }
123//! }
124//! ```
125//!
126//! The documentation for the C library states that `BAR_get_foo` returns a reference into the `BAR`
127//! passed to it, which translates into a reference in Rust. It also says that we're allowed to
128//! modify the `FOO`, so we'll define a pair of accessor methods, one immutable and one mutable:
129//!
130//! ```
131//! #[macro_use]
132//! extern crate foreign_types;
133//!
134//! use foreign_types::ForeignTypeRef;
135//!
136//! mod foo_sys {
137//!     pub enum FOO {}
138//!     pub enum BAR {}
139//!
140//!     extern {
141//!         pub fn FOO_free(foo: *mut FOO);
142//!         pub fn BAR_free(bar: *mut BAR);
143//!         pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO;
144//!     }
145//! }
146//!
147//! foreign_type! {
148//!     #[doc(hidden)]
149//!     type CType = foo_sys::FOO;
150//!     fn drop = foo_sys::FOO_free;
151//!     /// A Foo.
152//!     pub struct Foo;
153//!     /// A borrowed Foo.
154//!     pub struct FooRef;
155//! }
156//!
157//! foreign_type! {
158//!     type CType = foo_sys::BAR;
159//!     fn drop = foo_sys::BAR_free;
160//!     /// A Foo.
161//!     pub struct Bar;
162//!     /// A borrowed Bar.
163//!     pub struct BarRef;
164//! }
165//!
166//! impl BarRef {
167//!     fn foo(&self) -> &FooRef {
168//!         unsafe { FooRef::from_ptr(foo_sys::BAR_get_foo(self.as_ptr())) }
169//!     }
170//!
171//!     fn foo_mut(&mut self) -> &mut FooRef {
172//!         unsafe { FooRef::from_ptr_mut(foo_sys::BAR_get_foo(self.as_ptr())) }
173//!     }
174//! }
175//!
176//! # fn main() {}
177//! ```
178#![no_std]
179#![warn(missing_docs)]
180#![doc(html_root_url="https://docs.rs/foreign-types/0.3")]
181extern crate foreign_types_shared;
182
183#[doc(inline)]
184pub use foreign_types_shared::*;
185
186/// A macro to easily define wrappers for foreign types.
187///
188/// # Examples
189///
190/// ```
191/// #[macro_use]
192/// extern crate foreign_types;
193///
194/// # mod openssl_sys { pub type SSL = (); pub unsafe fn SSL_free(_: *mut SSL) {} pub unsafe fn SSL_dup(x: *mut SSL) -> *mut SSL {x} }
195/// foreign_type! {
196///     type CType = openssl_sys::SSL;
197///     fn drop = openssl_sys::SSL_free;
198///     fn clone = openssl_sys::SSL_dup;
199///     /// Documentation for the owned type.
200///     pub struct Ssl;
201///     /// Documentation for the borrowed type.
202///     pub struct SslRef;
203/// }
204///
205/// # fn main() {}
206/// ```
207#[macro_export]
208macro_rules! foreign_type {
209    (
210        $(#[$impl_attr:meta])*
211        type CType = $ctype:ty;
212        fn drop = $drop:expr;
213        $(fn clone = $clone:expr;)*
214        $(#[$owned_attr:meta])*
215        pub struct $owned:ident;
216        $(#[$borrowed_attr:meta])*
217        pub struct $borrowed:ident;
218    ) => {
219        $(#[$owned_attr])*
220        pub struct $owned(*mut $ctype);
221
222        $(#[$impl_attr])*
223        impl $crate::ForeignType for $owned {
224            type CType = $ctype;
225            type Ref = $borrowed;
226
227            #[inline]
228            unsafe fn from_ptr(ptr: *mut $ctype) -> $owned {
229                $owned(ptr)
230            }
231
232            #[inline]
233            fn as_ptr(&self) -> *mut $ctype {
234                self.0
235            }
236        }
237
238        impl Drop for $owned {
239            #[inline]
240            fn drop(&mut self) {
241                unsafe { $drop(self.0) }
242            }
243        }
244
245        $(
246            impl Clone for $owned {
247                #[inline]
248                fn clone(&self) -> $owned {
249                    unsafe {
250                        let handle: *mut $ctype = $clone(self.0);
251                        $crate::ForeignType::from_ptr(handle)
252                    }
253                }
254            }
255
256            impl ::std::borrow::ToOwned for $borrowed {
257                type Owned = $owned;
258                #[inline]
259                fn to_owned(&self) -> $owned {
260                    unsafe {
261                        let handle: *mut $ctype = $clone($crate::ForeignTypeRef::as_ptr(self));
262                        $crate::ForeignType::from_ptr(handle)
263                    }
264                }
265            }
266        )*
267
268        impl ::std::ops::Deref for $owned {
269            type Target = $borrowed;
270
271            #[inline]
272            fn deref(&self) -> &$borrowed {
273                unsafe { $crate::ForeignTypeRef::from_ptr(self.0) }
274            }
275        }
276
277        impl ::std::ops::DerefMut for $owned {
278            #[inline]
279            fn deref_mut(&mut self) -> &mut $borrowed {
280                unsafe { $crate::ForeignTypeRef::from_ptr_mut(self.0) }
281            }
282        }
283
284        impl ::std::borrow::Borrow<$borrowed> for $owned {
285            #[inline]
286            fn borrow(&self) -> &$borrowed {
287                &**self
288            }
289        }
290
291        impl ::std::convert::AsRef<$borrowed> for $owned {
292            #[inline]
293            fn as_ref(&self) -> &$borrowed {
294                &**self
295            }
296        }
297
298        $(#[$borrowed_attr])*
299        pub struct $borrowed($crate::Opaque);
300
301        $(#[$impl_attr])*
302        impl $crate::ForeignTypeRef for $borrowed {
303            type CType = $ctype;
304        }
305    }
306}