From 2e8cf0dca3a94f9553248102c94fbf32ed639b2f Mon Sep 17 00:00:00 2001 From: Anthony Reinette Date: Thu, 12 Mar 2020 17:49:04 +0100 Subject: [PATCH] Update README.md --- README.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/README.md b/README.md index ded6865..453a568 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,130 @@ # snips-utils-rs +This crate provides a framework to convert idiomatic Rust structs to C-like structs that can pass through an FFI boundary, and conversely. + +This framework is made up of two **conversion traits**, **`CReprOf`** and **`AsRust`**. +They ensure that the developper uses best practices when performing the conversion in both directions (ownership-wise). + +The crate also provides a collection of useful utility functions to perform conversions of types. +It goes hand in hand with the `ffi-utils-derive` as it provides an **automatic derivation** of the `CReprOf` and `AsRust` trait. + +## Usage + +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 definining the fields of the Pizza struct : + +``` +pub struct Pizza { + pub name: String, + pub toppings: Vec, + pub base: Option, + pub weight: f32, +} +``` + +We then create the C-like struct by mapping idiomatic Rust types to C compatible types : + +``` +#[repr(C)] +pub struct CPizza { + pub name: *const libc::c_char, + pub toppings: *const CArray, + 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. + +``` + CPizza::c_repr_of(pizza) + <=================| + +CPizza Pizza + + |=================> + cpizza.as_rust() + +``` + +Instead of manually writing the body of the conversion traits, we can derive them : + +``` +#[repr(C)] +#[derive(CReprOf, AsRust, CDrop)] +#[target_type(Pancake)] +pub struct CPizza { + pub name: *const libc::c_char, + pub toppings: *const CArray, + pub base: *const CSauce, + pub weight: libc::c_float, +} +``` + +You can now pass the `CPizza` struct through your FFI boundary ! + +## Example +BONUS if you can provide an example that you can copy/paste + +## Types representations mapping + +See definitions below this table. + +| C type | Rust type | C-compatible Rust type | +|:-----------:|:---------:|:--------------------------------------------:| +| const char* | String | *const libc::c_char | +| const T* | Option | *const T (with #[nullable] field annotation) | +| CArrayT | Vec | CArray | + + +``` +typedef struct { + const CSlotValue *slot_values; // Pointer to the first slot value of the list + int32_t size; // Number of T values in the list +} CArrayT; + +``` + +## The CReprOf trait + +The `CReprOf` trait allows to create a C-compatible representation of the reciprocal idiomatic Rust struct by consuming the latter. + +``` +pub trait CReprOf: Sized + CDrop { + fn c_repr_of(input: T) -> Result; +} +``` + +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 : + +``` +pub trait AsRust { + fn as_rust(&self) -> Result; +} + +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 form 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. + + +## Caveats with derivation of CReprOf and AsRust traits +TBD + ## License Licensed under either of