c_bridge 0.2.0

Some data structures and abstractions to create clean Rust<->C-FFI interfaces
Documentation
[![docs.rs](https://docs.rs/c_bridge/badge.svg)](https://docs.rs/c_bridge)
[![License BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause)
[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![crates.io](https://img.shields.io/crates/v/c_bridge.svg)](https://crates.io/crates/c_bridge)
[![Download numbers](https://img.shields.io/crates/d/c_bridge.svg)](https://crates.io/crates/c_bridge)
[![Travis CI](https://travis-ci.org/KizzyCode/c_bridge.svg?branch=master)](https://travis-ci.org/KizzyCode/c_bridge)
[![AppVeyor CI](https://ci.appveyor.com/api/projects/status/github/KizzyCode/c_bridge?svg=true)](https://ci.appveyor.com/project/KizzyCode/c-bridge)
[![dependency status](https://deps.rs/crate/c_bridge/0.1.0/status.svg)](https://deps.rs/crate/c_bridge/0.1.0)

# About `c_bridge`
This crate provides some data structures and abstractions to create clean Rust <-> C FFI interfaces

# The FFI Object
This is an in-depth overview over the FFI object and the semantics behind it:
 - [Concept]#concept
    - [Typing]#typing
       - [Predefined Types]#predefined-types
          - [Data Array]#data-array
          - [Object Array]#object-array
          - [Rust Object]#rust-object
    - [Ownership]#ownership
    - [Optionality]#optionality
    - [The FFI Result Type]#the-ffi-result-type
       - [OK-Variant]#ok-variant
       - [Error-Variant]#error-variant

## Concept
Each element is passed in an FFI object struct which looks like this and provides the following
properties:
 - Layout:
   ```c
   typedef struct {
       uint64_t type;
       void(*dealloc)(ffi_object_t*);
       void* payload;
   } ffi_object_t;
   ```
 - Typing: each FFI object provides information about the payload object's type
 - Ownership: each FFI object provides information about whether the the ownership is tied to the
   FFI object or if the object is just a reference to a payload object owned by someone else
 - Optionality: each FFI object may or may not contain a payload object

### Typing
Each FFI object contains a `uint64_t` field with a type ID which specifies the type of the payload.
The ID range is split into two segments:
 - `[0x0000000000000000, 0x8000000000000000)`: A range reserved for predefined types
 - `[0x8000000000000000, 0xffffffffffffffff]`: A range reserved for implementation defined types

#### Predefined Types
 - `0x0000000000000000`: An opaque type. This type is special because it indicates that the FFI
   object deliberately carries no type information and that it's `object` must not be interpreted
   unless you *know* it's type
 - `0x0000000000000001`: A [data array]#data-array with this layout:
   ```c
   typedef struct {
       uint8_t* data;
       size_t len;
   } data_array_t;
   ```
 - `0x0000000000000002`: An [object array]#object-array with this layout:
   ```c
   typedef struct {
       ffi_object_t* objects;
       size_t len;
   } object_array_t;
   ```
 - `0x0000000000000010`: A [Rust box]#rust-object containing an owned Rust object
   (`Box<dyn Any + 'static>`)

##### Data Array
The data array is a simple struct which contains a pointer to some data and a length field. The
pointer __must never__ be reallocated and must be deallocated by the FFI object's `dealloc`-function
__only__.

Layout:
```c
typedef struct {
    uint8_t* data;
    size_t len;
} data_array_t;
```

##### Object Array
The object array is a simple struct which contains a pointer to some some object structs and a
length field. The pointer __must never__ be reallocated and must be deallocated by the FFI object's
`dealloc`-function __only__.

Layout:
```c
typedef struct {
    ffi_object_t* objects;
    size_t len;
} object_array_t;
```

##### Rust Object
The Rust object is a pointer to a `Box<dyn Any + 'static>` which may typesafely contain an arbitrary
Rust object.
 
### Ownership
Since in the C world memory management happens manually, attention must be payed to questions like
"Who owns the object" and "How do I release this object", which can be especially tedious if we need
to cross FFI boundaries. To reduce this problem, we add explicit ownership information to each FFI
object using the `dealloc` field:
 - If the `dealloc` field is non-null, this means that the FFI object is owned by itself and must be
   released by passing it to it's `dealloc` function
 - If the `dealloc` field is null, the underlying `object` is managed by someone else

If the FFI object is owned, some care must be taken to avoid problems like double-free or
use-after-free:
 - Don't copy an owned FFI object
 - If you need to copy an FFI object, ensure that the shorter living one is unowned
 - If you move the payload object out of the FFI object, set the `dealloc` and `object` fields to
   null

### Optionality
Each FFI object has an optional payload object. This is necessary to be able to move something out
of the object (see [Ownership](#ownership) for more information).

Optionality is represented in the most simple way possible:
 - An existing payload object is represented as a non-null pointer to the object
 - An empty FFI object is represented by a null pointer as payload object


## The FFI Result Type
Together with the [FFI object](#the-ffi-object), we introduce another top-level type, the
`ffi_result_t`:
```c
typedef struct {
    ffi_object_t ok;
    ffi_object_t err;
} ffi_result_t;
```

This result type is similar to Rust's result and it's purpose is the same: The ability to return
either a good result or some error information without error-pointer-arguments and other
workarounds.

### OK-Variant
To construct an ok-variant, set the `ok`-field to your result and set the `err`-field to an [emtpy
FFI object](#optionality).

Note: if the `err`-field contains an empty FFI object, the FFI result must always be treated as ok -
even if the `ok`-field contains an empty FFI object (this is to be able to mimic Rust's
`Result<(), E>`).

### Error-Variant
To construct an error-variant, set the `err`-field to a [__non-emtpy__ FFI object](#optionality)
which contains your error and set the `ok`-field to an empty FFI object.