#ffi #no-std #framework #safety #bindings

no-std safer-ffi

Write safer FFI code in Rust without polluting it with unsafe code

12 releases

0.0.10 May 20, 2022
0.0.9 May 16, 2022
0.0.7 Mar 3, 2022
0.0.6 May 21, 2021
0.0.0 May 29, 2020

#1 in #safety

Download history 1599/week @ 2022-04-27 1461/week @ 2022-05-04 1429/week @ 2022-05-11 1424/week @ 2022-05-18 785/week @ 2022-05-25 1614/week @ 2022-06-01 1259/week @ 2022-06-08 976/week @ 2022-06-15 2312/week @ 2022-06-22 2581/week @ 2022-06-29 2192/week @ 2022-07-06 1967/week @ 2022-07-13 1790/week @ 2022-07-20 1892/week @ 2022-07-27 1936/week @ 2022-08-03 1281/week @ 2022-08-10

7,188 downloads per month
Used in 4 crates

MIT license

200KB
5.5K SLoC

safer-ffi-banner

CI guide docs-rs crates-io repository

What is safer_ffi?

safer_ffi is a framework that helps you write foreign function interfaces (FFI) without polluting your Rust code with unsafe { ... } code blocks while making functions far easier to read and maintain.

📚 Read The User Guide 📚

Prerequisites

Minimum Supported Rust Version: 1.56.0

Quickstart

Cargo.toml

Edit your Cargo.toml like so:

[package]
name = "crate_name"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]

[dependencies]
safer-ffi = { version = "*", features = ["proc_macros"] }

[features]
c-headers = ["safer-ffi/headers"]
  • Where "*" ought to be replaced by the last released version, which you can find by running cargo search safer-ffi.

src/lib.rs

use ::safer_ffi::prelude::*;

/// A `struct` usable from both Rust and C
#[derive_ReprC]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Point {
    x: f64,
    y: f64,
}

/* Export a Rust function to the C world. */
/// Returns the middle point of `[a, b]`.
#[ffi_export]
fn mid_point(a: &Point, b: &Point) -> Point {
    Point {
        x: (a.x + b.x) / 2.,
        y: (a.y + b.y) / 2.,
    }
}

/* Export a Rust enum to C */
#[ffi_export] // directly exporting a type is only needed
              // if no exported function mentions it
#[derive_ReprC]
#[repr(u8)]
pub enum Figure {
	Circle,
	Square
}

/// Pretty-prints a point using Rust's formatting logic.
#[ffi_export]
fn print_point(point: &Point) {
    println!("{:?}", point);
}

/// The following test function is necessary for the header generation.
#[::safer_ffi::cfg_headers]
#[test]
fn generate_headers() -> ::std::io::Result<()> {
    ::safer_ffi::headers::builder()
        .to_file("rust_points.h")?
        .generate()
}

Compilation & header generation

# Compile the C library (in `target/{debug,release}/libcrate_name.ext`)
cargo build # --release

# Generate the C header
cargo test --features c-headers -- generate_headers
Generated C header
/*! \file */
/*******************************************
 *                                         *
 *  File auto-generated by `::safer_ffi`.  *
 *                                         *
 *  Do not manually edit this file.        *
 *                                         *
 *******************************************/

#ifndef __RUST_CRATE_NAME__
#define __RUST_CRATE_NAME__

#ifdef __cplusplus
extern "C" {
#endif

/** \brief
 *  A `struct` usable from both Rust and C
 */
typedef struct {

    double x;

    double y;

} Point_t;

/** \brief
 *  Returns the middle point of `[a, b]`.
 */
Point_t mid_point (
    Point_t const * a,
    Point_t const * b);

typedef enum Figure
{
	FIGURE_CIRCLE,
	FIGURE_SQUARE
} Figure_t;


/** \brief
 *  Pretty-prints a point using Rust's formatting logic.
 */
void print_point (
    Point_t const * point);


#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __RUST_CRATE_NAME__ */

Testing it

main.c

#include <stdlib.h>

#include "rust_points.h"

int main (int argc, char const * const argv[])
{
    Point_t a = { .x = 84, .y = 45 };
    Point_t b = { .x = 0, .y = 39 };
    Point_t m = mid_point(&a, &b);
    print_point(&m);
    return EXIT_SUCCESS;
}

Compilation command

cc main.c -o main -L target/debug -l crate_name -l pthread -l dl

# Now feel free to run the compiled binary
./main

which outputs:

Point { x: 42.0, y: 42.0 }

🚀🚀

Dependencies

~160KB