1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! A collection of utilities (traits, data structures, conversion functions, etc ...) to ease conversion between Rust and C-compatible data structures.
//!
//! Through two **conversion traits**, [`CReprOf`] and [`AsRust`], this crate provides a framework to convert idiomatic Rust structs to C-compatible structs that can pass through an FFI boundary, and conversely.
//! They ensure that the developer uses best practices when performing the conversion in both directions (ownership-wise).
//!
//! The crate also provides a collection of useful utility functions and traits to perform conversions of types.
//! It goes hand in hand with the `ffi-convert-derive` crate as it provides an **automatic derivation** of the [`CReprOf`] and [`AsRust`] trait.
//!
//! # Usage
//! When dealing with an FFI frontier, the general philosophy of the crate is :  
//! - When receiving pointers to structs created by C code, the struct is immediately converted to an owned (via a copy), idiomatic Rust struct through the use of the [`AsRust`] trait.
//! - To send an idiomatic, owned Rust struct to C code, the struct is converted to C-compatible representation using the [`CReprOf`] trait.
//!
//! ## Example
//!
//! We want to be able to convert a **`Pizza`** Rust struct that has an idiomatic representation to a **`CPizza`** Rust struct that has a C-compatible representation in memory.
//! We start by defining the fields of the `Pizza` struct :
//! ```
//! # struct Topping {};
//! # struct Sauce {};
//! pub struct Pizza {
//!     pub name: String,
//!     pub toppings: Vec<Topping>,
//!     pub base: Option<Sauce>,
//!     pub weight: f32,
//! }
//!```
//!
//! We then create the C-compatible struct by [mapping](#types-representations-mapping) idiomatic Rust types to C-compatible types :
//! ```
//! # use ffi_convert::CArray;
//! # struct CTopping {};
//! # struct CSauce {};
//! #[repr(C)]
//! pub struct CPizza {
//!     pub name: *const libc::c_char,
//!     pub toppings: *const CArray<CTopping>,
//!     pub base: *const CSauce,
//!     pub weight: libc::c_float,
//! }
//! ```
//!
//! This crate provides two traits that are useful for converting between Pizza to CPizza and conversely.
//!
//! ```ignore
//!    CPizza::c_repr_of(pizza)
//!      <=================|
//!
//! CPizza                   Pizza
//!
//!      |=================>
//!       cpizza.as_rust()
//!
//! ```
//! Instead of manually writing the body of the conversion traits, we can derive them :
//!
//! ```
//! # use ffi_convert::{CReprOf, AsRust, CDrop, RawPointerConverter};
//! # use ffi_convert::CArray;
//! # use ffi_convert::RawBorrow;
//! # struct Topping {};
//! # #[derive(CReprOf, AsRust, CDrop)]
//! # #[target_type(Topping)]
//! # struct CTopping {};
//! #
//! # struct Pizza {
//! #     name: String,
//! #     toppings: Vec<Topping>,
//! #     base: Sauce,
//! #     weight: f32
//! # };
//! use libc::{c_char, c_float};
//!
//! struct Sauce {};
//! #[derive(CReprOf, AsRust, CDrop, RawPointerConverter)]
//! #[target_type(Sauce)]
//! struct CSauce {};
//!
//! #[repr(C)]
//! #[derive(CReprOf, AsRust, CDrop)]
//! #[target_type(Pizza)]
//! pub struct CPizza {
//!     pub name: *const c_char,
//!     pub toppings: *const CArray<CTopping>,
//!     pub base: *const CSauce,
//!     pub weight: c_float,
//! }
//! ```
//!
//! You may have noticed that you have to derive two traits : the CDrop trait and the RawPointerConverter trait.
//!
//! The CDrop trait needs to be implemented on every C-compatible struct that require manual resource management.
//! The release of those resources should be done in the drop method of the CDrop trait.
//!
//! The RawPointerConverter trait is implemented to perform the conversion of a C-like struct to a raw-pointer to this C-like structure (and conversely).
//! Here, it is used behind the scene to convert a `CSauce` struct to a pointer to a raw pointer to CSause struct : `*const CSauce`
//! (needed behind the scenes when the [`CReprOf`] trait is derived for `CPizza`).
//!
//! You can now pass the `CPizza` struct through your FFI boundary !
//!

//! ## Types representations mapping
//!
//! `T : CReprOf<U> + AsRust<U>`
//! <table>
//!     <thead>
//!         <tr>
//!             <th>C type</th>
//!             <th>Rust type</th>
//!             <th>C-compatible Rust type</th>
//!         </tr>
//!     </thead>
//!     <tbody>
//!         <tr>
//!             <td><code>const char*</code></td>
//!             <td><code>String</code></td>
//!             <td><code>*const libc::c_char</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>const T*</code></td>
//!             <td><code>U</code></td>
//!             <td><code>*const T</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>T*</code></td>
//!             <td><code>U</code></td>
//!             <td><code>*mut T</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>T</code></td>
//!             <td><code>U</code></td>
//!             <td><code>T</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>const T*</code></td>
//!             <td><code>Option&lt;U&gt;</code></td>
//!             <td><code>*const T</code> (with <code>#[nullable]</code> field annotation)</td>
//!         </tr>
//!         <tr>
//!             <td><code>CArrayT</code></td>
//!             <td><code>Vec&lt;U&gt;</code></td>
//!             <td><code>CArray&lt;T&gt;</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>CStringArray</code></td>
//!             <td><code>Vec&lt;String&gt;</code></td>
//!             <td><code>CStringArray</code></td>
//!         </tr>
//!         <tr>
//!             <td><code>CRangeT</code></td>
//!             <td><code>Range&lt;U&gt;</code></td>
//!             <td><code>CRange&lt;T&gt;</code></td>
//!         </tr>
//!     </tbody>
//! </table>
//!

//! ## The CReprOf trait

//! The `CReprOf` trait allows to create a C-compatible representation of the reciprocal idiomatic Rust struct by consuming the latter.

//! ```
//! # use ffi_convert::{CReprOfError, CDrop};
//! pub trait CReprOf<T>: Sized + CDrop {
//!     fn c_repr_of(input: T) -> Result<Self, CReprOfError>;
//! }
//! ```

//! This shows that the struct implementing it is a `repr(C)` compatible view of the parametrized
//! type and can be created from an object of this type.

//! ## The AsRust trait

//! > When trying to convert a `repr(C)` struct that originated from C, the philosophy is to immediately convert
//! > the struct to an **owned** idiomatic representation of the struct via the AsRust trait.

//! The [`AsRust`] trait allows to create an idiomatic Rust struct from a C-compatible struct :

//! ```
//! # use ffi_convert::{AsRustError, CDrop};
//! pub trait AsRust<T> {
//!     fn as_rust(&self) -> Result<T, AsRustError>;
//! }
//! ```

//! This shows that the struct implementing it is a `repr(C)` compatible view of the parametrized
//! type and that an instance of the parametrized type can be created from this struct.

//! ## The CDrop trait

//! A Trait showing that the `repr(C)` compatible view implementing it can free up its part of memory that are not
//! managed by Rust drop mechanism.

//! ## The RawPointerConverter trait

//! This trait completes the conversion traits toolbox provided by this crate : It expresses the
//! conversion of a C-like struct to a raw pointer to this struct and conversely.
//!
//! This conversion trait comes in handy for C-like struct that have fields that points to other structs.

pub use ffi_convert_derive::*;

mod conversions;
mod types;

pub use conversions::*;
pub use types::*;