integrations/README.md
2026-03-27 09:20:31 +01:00

2.8 KiB

Integrations


This repository is a small Rust/Haskell interop demo.

The current project demonstrates communication in both directions:

  • Haskell calling into Rust through a C ABI exposed by the Rust crate
  • Rust calling back into Haskell through a Cabal foreign-library

The code is intentionally small. The goal is to show the main integration mechanics and the main failure points without adding code generation or a large build stack.

What The Demo Contains

  • rust/ - Rust exports a C ABI for Haskell and provides a CLI path that loads and calls the Haskell shared library
  • haskell/ - Haskell contains a small Cabal project with:
    • an executable that calls Rust
    • a shared foreign library that Rust calls
    • small pure tests for the shared Haskell-side logic

The boundary is deliberately C-shaped:

  • integers
  • a shared struct layout
  • borrowed slices as ptr + len
  • owned buffers as ptr + len + cap
  • owned C strings with explicit free functions on each side

The current examples cover:

  • scalar values and shared structs
  • borrowed i32 slices
  • owned i32 buffers returned across the boundary
  • borrowed raw byte buffers
  • owned raw byte buffers returned across the boundary

The byte examples are separate from C strings on purpose. They demonstrate handling embedded zero bytes safely.

Why The Build Uses Both Static And Shared Libraries

This demo uses different library styles for the two directions because that keeps each path simpler:

  • Haskell -> Rust uses the Rust crate as a static library
  • Rust -> Haskell uses a Haskell shared foreign library that Rust loads at runtime

That is not the only possible design. It is just a practical one for a two-way demo.

Build And Run

Build the Haskell project and the Rust library it links against:

make haskell-build

Run the Haskell -> Rust demo:

make haskell-run

Run the Rust -> Haskell demo:

make rust-calls-haskell

You can also run the underlying commands directly:

cargo test
cd haskell
CABAL_DIR=$PWD/../.cabal XDG_STATE_HOME=$PWD/../.cabal/state XDG_CACHE_HOME=$PWD/../.cabal/cache XDG_CONFIG_HOME=$PWD/../.cabal/config cabal test --project-file=cabal.project

What This Project Demonstrates

  • the ABI boundary must stay simple and explicit
  • Rust and Haskell do not share ownership rules automatically
  • struct layout must match on both sides
  • borrowed data and owned returned buffers need different FFI patterns
  • raw bytes are not the same thing as C strings
  • Rust calling Haskell is the harder direction because it must initialize the GHC runtime correctly
  • build tooling is part of the integration problem, not just an implementation detail

License

This project is licensed under either of these: