hs_bindgen/
lib.rs

1//! # `hs-bindgen`
2//!
3//! Handy macro to generate C-FFI bindings to Rust for Haskell.
4//!
5//! This library intended to work best in a project configured by
6//! [`cargo-cabal`](https://github.com/yvan-sraka/cargo-cabal).
7//!
8//! **N.B.** The MSRV is **1.64.0** since it use `core_ffi_c` feature.
9//!
10//! ## Examples
11//!
12//! A minimal example would be to have a function annotated like this:
13//!
14//! ```rust
15//! use hs_bindgen::*;
16//!
17//! /// Haskell type signatures are auto-magically inferred from Rust function
18//! /// types! This feature could slow down compilation, and be enabled with:
19//! /// `hs-bindgen = { ..., features = [ "full" ] }`
20//! #[hs_bindgen]
21//! fn greetings(name: &str) {
22//!     println!("Hello, {name}!");
23//! }
24//! ```
25//!
26//! This will be expanded to (you can try yourself with `cargo expand`):
27//!
28//! ```rust
29//! use hs_bindgen::*;
30//!
31//! fn greetings(name: &str) {
32//!     println!("Hello, {name}!");
33//! }
34//!
35//! #[no_mangle] // Mangling makes symbol names more difficult to predict.
36//!              // We disable it to ensure that the resulting symbol is really `__c_greetings`.
37//! extern "C" fn __c_greetings(__0: *const core::ffi::c_char) -> () {
38//!     // `traits` module is `hs-bindgen::hs-bindgen-traits`
39//!     // n.b. do not forget to import it, e.g., with `use hs-bindgen::*`
40//!     traits::FromReprC::from(greetings(traits::FromReprRust::from(__0),))
41//! }
42//! ```
43//!
44//! A more complete example, when we now try to pass a custom type to our
45//! interface:
46//!
47//! ```rust
48//! use hs_bindgen::{traits::FromReprRust, *};
49//! use std::marker::PhantomData;
50//!
51//! /// A custom Rust data-type, `#[repr(transparent)]` is not useful here
52//! /// since `FromReprRust` trait will offers the constructor we need to construct
53//! /// our type out of a C-FFI safe primitive data-structure.
54//! struct User<T: Kind> {
55//!     name: String,
56//!     kind: PhantomData<T>,
57//! }
58//!
59//! /** Overly engineered traits definitions just for the sake of demonstrating
60//! limitations of this example, this isn't at all needed by default */
61//!
62//! struct Super;
63//!
64//! trait Kind {
65//!     fn greet(name: &str) -> String;
66//! }
67//!
68//! impl Kind for Super {
69//!     fn greet(name: &str) -> String {
70//!         format!("Hello, {}!", name)
71//!     }
72//! }
73//!
74//! /// Declare targeted Haskell signature, return types should be wrapped in
75//! /// an IO Monad (a behavior enforced by safety concerns)
76//! #[hs_bindgen(hello :: CString -> IO CString)]
77//! fn hello(user: User<Super>) -> String {
78//!     Super::greet(&user.name)
79//! }
80//!
81//! /** n.b. functions wrapped by `#[hs_bindgen]` macro couldn't be
82//! parametrized by generics (because monomorphisation occurs after macro
83//! expansion during compilation, and how rustc assign unmangled symbols to
84//! monomorphised methods are AFAIK not a publicly specified behavior), but
85//! this limitation didn’t apply to `hs-bindgen-traits` implementations! */
86//!
87//! impl<T: Kind> FromReprRust<*const i8> for User<T> {
88//!     fn from(ptr: *const i8) -> Self {
89//!         User::<T> {
90//!             name: <String as FromReprRust<*const i8>>::from(ptr),
91//!             kind: PhantomData::<T>
92//!         }
93//!     }
94//! }
95//! ```
96//!
97//! ## Design
98//!
99//! First, I would thank [Michael Gattozzi](https://twitter.com/mgattozzi) who
100//! implement [a (no longer maintained) implementation](https://github.com/mgattozzi/curryrs)
101//! to binding generation between Rust and Haskell and
102//! [his writings](https://blog.mgattozzi.dev/haskell-rust/) and guidance
103//! really help me to quick start this project.
104//!
105//! I try to architect `hs-bindgen` with these core design principles:
106//!
107//! - **Simplicity:** as KISS UNIX philosophy of minimalism, meaning here I
108//!   tried to never re-implement feature already handled by Rust programming
109//!   language (parsing code, infer types, etc.), I rather rely on capabilities
110//!   of macro and trait systems. E.g. the only bit of parsing left in this
111//!   code its Haskell function signature (which is trivial giving the feature
112//!   set of authorized C-FFI safe types) ;
113//!
114//! - **Modularity:** this library is design in mind to work in a broader range
115//!   of usage, so this library should work in `#[no_std]` setting and most
116//!   features could be opt-out. E.g. the type inference offered by
117//!   [`antlion`](https://github.com/yvan-sraka/antlion) library is optional ;
118//!
119//! - **Stability:** this library implements no trick outside the scope of
120//!   stable C ABI (with well-defined memory layout convention), and ensure to
121//!   provide ergonomics without breaking this safety rule of thumb. There is
122//!   no magic that could be break by any `rustc` or GHC update!
123//!
124//! ## Acknowledgments
125//!
126//! ⚠️ This is still a working experiment, not yet production ready.
127//!
128//! `hs-bindgen` was heavily inspired by other interoperability initiatives, as
129//! [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) and
130//! [`PyO3`](https://github.com/PyO3/pyo3).
131//!
132//! This project was part of a work assignment as an
133//! [IOG](https://github.com/input-output-hk) contractor.
134//!
135//! ## License
136//!
137//! Licensed under either of [Apache License](LICENSE-APACHE), Version 2.0 or
138//! [MIT license](LICENSE-MIT) at your option.
139//!
140//! Unless you explicitly state otherwise, any contribution intentionally submitted
141//! for inclusion in this project by you, as defined in the Apache-2.0 license,
142//! shall be dual licensed as above, without any additional terms or conditions.
143
144#![forbid(unsafe_code)]
145
146pub use hs_bindgen_attribute::hs_bindgen;
147pub use hs_bindgen_traits as traits;