[][src]Crate ffi_convert

A collection of utilities (functions, traits, data structures, 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 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-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, 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 definining the fields of the Pizza struct :

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 idiomatic Rust types to C-compatible types :

#[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.

This example is not tested
   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 libc::{c_char, c_float};

#[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 the CDrop 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.

You can now pass the CPizza struct through your FFI boundary !

Types representations mapping

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
This example is not tested
typedef struct {
const T *values; // Pointer to the 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<T>: Sized + CDrop {
    fn c_repr_of(input: T) -> Result<Self, Error>;
}

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<T> {
    fn as_rust(&self) -> Result<T, Error>;
}

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 drop mechanism.

Caveats with derivation of CReprOf and AsRust traits

Macros

convert_to_c_string

A macro to convert a std::String to a C-compatible representation : a raw pointer to libc::c_char. After calling this function, the caller is responsible for releasing the memory. The take_back_c_string! macro can be used for releasing the memory.

convert_to_c_string_array

A macro to convert a Vec<String> to a C-compatible representation : a raw pointer to a CStringArray After calling this function, the caller is responsible for releasing the memory. The take_back_c_string_array! macro can be used for releasing the memory.

convert_to_c_string_result

A macro to convert a std::String to a C-compatible representation a raw pointer to libc::c_char wrapped in a Result enum. After calling this function, the caller is responsible for releasing the memory. The take_back_c_string! macro can be used for releasing the memory.

convert_to_nullable_c_string

A macro to convert an Option<String> to a C-compatible representation : a raw pointer to libc::c_char if the Option enum is of variant Some, or a null pointer if the Option enum is of variant None.

convert_to_nullable_c_string_array

A macro to convert a Vec<String> to a C-compatible representation : a raw pointer to a CStringArray After calling this function, the caller is responsible for releasing the memory. The take_back_c_string_array! macro can be used for releasing the memory.

create_optional_rust_string_from

Unsafely creates an optional owned string from a pointer to a nul-terminated array of bytes.

create_optional_rust_vec_string_from

Unsafely creates an optional array of owned string from a pointer to a CStringArray.

create_rust_string_from

Unsafely creates an owned string from a pointer to a nul-terminated array of bytes.

create_rust_vec_string_from

Unsafely creates an array of owned string from a pointer to a CStringArray.

take_back_c_string

Retakes the ownership of the memory pointed to by a raw pointer to a libc::c_char

take_back_c_string_array

Retakes the ownership of the memory storing an array of C-compatible strings

take_back_nullable_c_string

Retakes the ownership of the memory pointed to by a raw pointer to a libc::c_char, checking first if the pointer is not null.

take_back_nullable_c_string_array

Retakes the ownership of the memory storing an array of C-compatible strings, checking first if the provided pointer is not null.

Structs

CArray

A utility type to represent arrays of the parametrized type. Note that the parametrized type should have a C-compatible representation.

CRange

A utility type to represent range. Note that the parametrized type T should have have CReprOf and AsRust trait implementated.

CStringArray

A utility type to represent arrays of string

Error

The Error type, which can contain any failure.

Traits

AsRust

Trait showing 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

CDrop

Trait showing that the C-like struct implementing it can free up its part of memory that are not managed by Rust.

CReprOf

Trait showing that the struct implementing it is a repr(C) compatible view of the parametrized type that can be created from an object of this type.

RawBorrow

Trait to create borrowed references to type T, from a raw pointer to a T

RawBorrowMut

Trait to create mutable borrowed references to type T, from a raw pointer to a T

RawPointerConverter

Trait representing the creation of a raw pointer from a struct and the recovery of said pointer.

Functions

point_to_string

Derive Macros

AsRust
CDrop
CReprOf