cimpl 0.1.0

Adds build time type definitions for C-FFI signature checking
Documentation
cimpl-0.1.0 has been yanked.

cimpl

cimpl is a crate that ensures that the signatures of the functions in C you're implementing matches what C expects.

Why is this useful?

Lets say you have a library in C that requires you to write primitives for it to build up on,

#pragma once

void foo(uint64_t* fill_me);

Now this can be implemented in Rust using your usual C-FFI #[no_mangle] way although it doesn't guarantee any signature changes that may happen in the libraries requirements tomorrow. This results in complete undefined behavior (example: if it changes to void foo(uint32_t* fill_me) tomorrow you could be overflowing buffers 🚨🚨🚨). To ensure against C library fragility at compiletime, cimpl guarantees signature safety as long as the header files for the implementation can be generated at compile-time.

How to use?

build.rs changes

At build time it's required to add the cimpl post-processing step to ensure type definitions can be added into your autogenerated file.

std::fs::write_all(cimpl::derive("<bindgen_output>")).unwrap();

Before

extern "C" {
    pub fn foo() -> i32;
}

After

pub type __cimpl_foo = fn() -> i32;
extern "C" {
    pub fn foo() -> i32;
}

Implementation

#[cimpl::bind(bindgen::foo)]
#[no_mangle]
pub extern "C" fn foo() -> i32 {
    42_i32
}

This generates the following:

mod bindgen {
    const _: __cimpl_foo = foo; // Guarantees typeck verified signatures at compile-time
    #[no_mangle]
    pub extern "C" fn foo() -> i32 {
        42_i32
    }
}

TODOs

  • Create a nicer macro like derive to match with bind, this allows extern "C" function implementations to not be done at compile time, however this is likely a bug and requires design reconsiderations
  • Tests! I'm not too familiar with proc-macros to know how to do this without