hs-bindgen

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

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

N.B. The MSRV is 1.64.0 since we use core_ffi_c library feature.

Examples

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

```rust use hs_bindgen::*;

/// Haskell type signature are auto-magically inferred from Rust function /// type! This feature could slow down compilation and be disabled with: /// hs-bindgen = { ..., default-features = false }

[hs_bindgen]

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

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

```rust use hs_bindgen::*;

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

[no_mangle] // Mangling randomize symbols

extern "C" fn cgreetings(0: *const core::ffi::cchar) -> () { // 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:

```rust 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 { name: String, kind: PhantomData, }

/** 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) -> 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 ReprRust<*const i8> for User { fn from(ptr: *const i8) -> Self { User:: { name: >::from(ptr), kind: PhantomData:: } } } ```

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:

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.