Handy macro to generate C-FFI bindings to Rust for Haskell

Overview

hs-bindgen

Handy macro to generate C-FFI bindings to Rust for Haskell.

This library intended to work best in a project configured by cargo-cabal.

N.B. The MSRV is 1.64.0 since it use core_ffi_c feature.

Examples

A minimal example would be to have a function annotated like this:

use hs_bindgen::*;

/// Haskell type signatures are auto-magically inferred from Rust function
/// types! This feature could slow down compilation, and be enabled with:
/// `hs-bindgen = { ..., features = [ "full" ] }`
#[hs_bindgen]
fn greetings(name: &str) {
    println!("Hello, {name}!");
}

This will be expanded to (you can try yourself with cargo expand):

use hs_bindgen::*;

fn greetings(name: &str) {
    println!("Hello, {name}!");
}

#[no_mangle] // Mangling makes symbol names more difficult to predict.
             // We disable it to ensure that the resulting symbol is really `__c_greetings`.
extern "C" fn __c_greetings(__0: *const core::ffi::c_char) -> () {
    // `traits` module is `hs-bindgen::hs-bindgen-traits`
    // n.b. do not forget to import it, e.g., with `use hs-bindgen::*`
    traits::ReprC::from(greetings(traits::ReprRust::from(__0),))
}

A more complete example, when we now try to pass a custom type to our interface:

use hs_bindgen::{traits::ReprRust, *};
use std::marker::PhantomData;

/// A custom Rust data-type, `#[repr(transparent)]` is not useful here
/// since `ReprRust` trait will offers the constructor we need to construct
/// our type out of a C-FFI safe primitive data-structure.
struct User<T: Kind> {
    name: String,
    kind: PhantomData<T>,
}

/** Overly engineered traits definitions just for the sake of demonstrating
limitations of this example, this isn't at all needed by default */

struct Super;

trait Kind {
    fn greet(name: &str) -> String;
}

impl Kind for Super {
    fn greet(name: &str) -> String {
        format!("Hello, {}!", name)
    }
}

/// Declare targeted Haskell signature, return types should be wrapped in
/// an IO Monad (a behavior enforced by safety concerns)
#[hs_bindgen(hello :: CString -> IO CString)]
fn hello(user: User<Super>) -> String {
    Super::greet(&user.name)
}

/** n.b. functions wrapped by `#[hs_bindgen]` macro couldn't be
parametrized by generics (because monomorphisation occurs after macro
expansion during compilation, and how rustc assign unmangled symbols to
monomorphised methods are AFAIK not a publicly specified behavior), but
this limitation didn’t apply to `hs-bindgen-traits` implementations! */

impl<T: Kind> ReprRust<*const i8> for User<T> {
    fn from(ptr: *const i8) -> Self {
        User::<T> {
            name: <String as ReprRust<*const i8>>::from(ptr),
            kind: PhantomData::<T>
        }
    }
}

Design

First, I would thank Michael Gattozzi who implement a (no longer maintained) implementation to binding generation between Rust and Haskell and his writings and guidance really help me to quick start this project.

I try to architect hs-bindgen with these core design principles:

  • Simplicity: as KISS UNIX philosophy of minimalism, meaning here I tried to never re-implement feature already handled by Rust programming language (parsing code, infer types, etc.), I rather rely on capabilities of macro and trait systems. E.g. the only bit of parsing left in this code its Haskell function signature (which is trivial giving the feature set of authorized C-FFI safe types) ;

  • Modularity: this library is design in mind to work in a broader range of usage, so this library should work in #[no_std] setting and most features could be opt-out. E.g. the type inference offered by antlion library is optional ;

  • Stability: this library implements no trick outside the scope of stable C ABI (with well-defined memory layout convention), and ensure to provide ergonomics without breaking this safety rule of thumb. There is no magic that could be break by any rustc or GHC update!

Acknowledgments

⚠️ This is still a working experiment, not yet production ready.

hs-bindgen was heavily inspired by other interoperability initiatives, as wasm-bindgen and PyO3.

This project was part of a work assignment as an IOG contractor.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

You might also like...
zzhack-cli is a Command Tool to help you quickly generate a WASM WebApp with simple configuration and zero code
zzhack-cli is a Command Tool to help you quickly generate a WASM WebApp with simple configuration and zero code

English | 中文文档 zzhack-cli is a Command Tool that can help you quickly generate a WASM WebApp with simple configuration and zero code. It's worth menti

Rust based WASM/JS bindings for ur-rust

ur-wasm-js WASM/JS bindings for the ur-rust rust library Getting started Installation Either build the library yourself with wasm-pack or install for

A project for generating C bindings from Rust code

cbindgen   Read the full user docs here! cbindgen creates C/C++11 headers for Rust libraries which expose a public C API. While you could do this by h

Rust-JDBC bindings

jdbc A Rust library that allows you to use JDBC and JDBC drivers. Usage First, add the following to your Cargo.toml: [dependencies] jdbc = "0.1" Next,

Lua 5.3 bindings for Rust

rust-lua53 Aims to be complete Rust bindings for Lua 5.3 and beyond. Currently, master is tracking Lua 5.3.3. Requires a Unix-like environment. On Win

Safe Rust bindings to Lua 5.1

rust-lua Copyright 2014 Lily Ballard Description This is a set of Rust bindings to Lua 5.1. The goal is to provide a (relatively) safe interface to Lu

mruby safe bindings for Rust

mrusty. mruby safe bindings for Rust mrusty lets you: run Ruby 1.9 files with a very restricted API (without having to install Ruby) reflect Rust stru

Rust bindings for writing safe and fast native Node.js modules.
Rust bindings for writing safe and fast native Node.js modules.

Rust bindings for writing safe and fast native Node.js modules. Getting started Once you have the platform dependencies installed, getting started is

Objective-C Runtime bindings and wrapper for Rust.

Objective-C Runtime bindings and wrapper for Rust. Documentation: http://ssheldon.github.io/rust-objc/objc/ Crate: https://crates.io/crates/objc Messa

Rust-ffi-guide - A guide for doing FFI using Rust

Using unsafe for Fun and Profit A guide to traversing the FFI boundary between Rust and other languages. A rendered version is available here. This gu

Michael Bryan 261 Dec 1, 2022
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
libc - Raw FFI bindings to platforms' system libraries

libc provides all of the definitions necessary to easily interoperate with C code (or "C-like" code) on each of the platforms that Rust supports. This includes type definitions (e.g. c_int), constants (e.g. EINVAL) as well as function headers (e.g. malloc).

The Rust Programming Language 1.5k Jan 1, 2023
A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics.

ecu_diagnostics A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics. IMPORTANT Currently this crate is not 100% read

Ashcon Mohseninia 80 Dec 24, 2022
Bridge the gap between Haskell and Rust

Curryrs Curryrs (a play on the name of Haskell Curry, rs for Rust libraries, and it's pronunciation couriers) is a library for providing easy to use b

Michael Gattozzi 296 Oct 18, 2022
A macro to generate constructor to instanicate structs from JsValue using duck-typing.

ducktor ducktor is a Rust crate that allows you to create types from wasm_bindgen::JsValue using duck typing. With ducktor, you can define a struct th

Muhammad Hamza 6 Jun 23, 2023
A safe Rust FFI binding for the NVIDIA® Tools Extension SDK (NVTX).

NVIDIA® Tools Extension SDK (NVTX) is a C-based Application Programming Interface (API) for annotating events, code ranges, and resources in your applications. Official documentation for NVIDIA®'s NVTX can be found here.

Spencer Imbleau 78 Jan 2, 2023
Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# library.

Rabe-ffi Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# libra

Aya0wind 2 Oct 10, 2022
A rust proc-macro which allows for reading and writing to remote objects through a generated enum

Remote-Obj A rust proc-macro which allows for reading and writing fields/variants of (possibly nested) remote objects by generating a single enum whic

Ben Wang 5 Aug 11, 2022
witgen is a library to generate .wit files for WebAssembly in Rust

witgen witgen is a library to help you generate wit definitions in a wit file for WebAssembly. Using this lib in addition to wit-bindgen will help you

Coenen Benjamin 28 Nov 9, 2022