| 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" )] |
| 181 | extern crate foreign_types_shared; |
| 182 | |
| 183 | #[doc (inline)] |
| 184 | pub 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 ] |
| 208 | macro_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 | } |
| 307 | |