integrations/README.md

96 lines
2.8 KiB
Markdown
Raw Permalink Normal View History

2026-03-24 09:50:06 +01:00
## 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:
```sh
make haskell-build
```
Run the Haskell -> Rust demo:
```sh
make haskell-run
```
Run the Rust -> Haskell demo:
```sh
make rust-calls-haskell
```
You can also run the underlying commands directly:
```sh
cargo test
```
```sh
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
2026-03-24 09:50:06 +01:00
### License
This project is licensed under either of these:
* MIT License (see [LICENSE-MIT](LICENSE-MIT))
* Apache License, Version 2.0 (see [LICENSE-APACHE](LICENSE-APACHE))