2026-03-24 09:50:06 +01:00
|
|
|
# Garnet Findings
|
|
|
|
|
|
|
|
|
|
Date: 2026-03-24
|
|
|
|
|
|
|
|
|
|
Garnet repository: https://code.obsidian.systems/patrickaldis/garnet
|
|
|
|
|
|
|
|
|
|
## Summary
|
|
|
|
|
|
|
|
|
|
Garnet is a proof-of-concept for Rust/Haskell interop.
|
|
|
|
|
|
|
|
|
|
The repo is testing a specific pipeline:
|
|
|
|
|
|
|
|
|
|
Rust exports a C ABI -> `cbindgen` emits a header -> `hs-bindgen` produces Haskell bindings -> hand-written Haskell wrappers clean up the API.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The repo demonstrates the pipeline. It is not production-ready infrastructure.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## What It Contains
|
|
|
|
|
|
|
|
|
|
- `./tmp/garnet/rust/lib.rs` - Rust FFI examples: strings, structs, enums, arithmetic, recursive trees.
|
|
|
|
|
- `./tmp/garnet/rust/build.rs` - header generation plus a local patch for `hs-bindgen` compatibility.
|
|
|
|
|
- `./tmp/garnet/lib/GarnetRs/Raw.hs` - low-level binding generation from the generated header.
|
|
|
|
|
- `./tmp/garnet/lib/GarnetRs/Wrapped.hs` - Haskell-facing wrapper types and conversions.
|
|
|
|
|
- `./tmp/garnet/exe/Main.hs` - demo executable that exercises the bridge.
|
|
|
|
|
- `./tmp/garnet/build` - custom build glue for Cargo and Cabal.
|
|
|
|
|
|
|
|
|
|
## Review
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The architecture is clear. The split between raw bindings and wrapper code is appropriate. The examples cover more than trivial FFI cases.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The project is still early. The build is custom, the dependencies are pinned to git revisions, and the Rust build script contains a workaround for
|
|
|
|
|
upstream tooling issues. That is acceptable for an experiment, but it is a weak base for a maintained integration layer.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The main limitation is that code generation does not remove the manual work. The Haskell side still needs wrapper code to produce a usable API.
|
|
|
|
|
The repo shows that the pipeline works. It also shows that the workflow still has overhead.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Pros
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
- The architecture is easy to inspect.
|
|
|
|
|
- The examples cover multiple FFI cases.
|
|
|
|
|
- The split between generated and hand-written code is reasonable.
|
|
|
|
|
- The repo is small enough to review quickly.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Cons
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
- The build flow is manual.
|
2026-03-24 09:50:06 +01:00
|
|
|
- The setup depends on alpha-stage or pinned upstream tooling.
|
2026-03-24 14:24:30 +01:00
|
|
|
- The local header patch adds maintenance risk.
|
|
|
|
|
- The wrapper layer still requires manual boilerplate.
|
|
|
|
|
- There is no visible test, CI, or long-term maintenance plan.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Status
|
|
|
|
|
|
|
|
|
|
Current status: working prototype.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The repo is far enough along to prove the interop path and demonstrate the tooling choices. It is not far enough along to support repeated reuse
|
|
|
|
|
without more work on build integration, test coverage, and dependency stability.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
Reviewer verdict: useful experiment, not ready to treat as infrastructure.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Ecosystem Maturity
|
|
|
|
|
|
|
|
|
|
Rust/Haskell interop is uneven.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The low-level foundation is mature enough. Haskell has had an FFI story for years, and Rust can export or import a C ABI.
|
2026-03-24 09:50:06 +01:00
|
|
|
If the boundary is narrow and C-like, the approach is viable.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
The weak part is the tooling layer. Header generation on the Rust side is usable. Binding generation on the Haskell side is improving, but it
|
2026-03-24 09:50:06 +01:00
|
|
|
still looks early. The Garnet repo reflects that gap exactly: the ABI path works, but the workflow still needs custom glue and hand-written cleanup.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
Reviewer verdict: usable for a disciplined team, not easy.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Calling Direction
|
|
|
|
|
|
|
|
|
|
### Calling Rust From Haskell
|
|
|
|
|
|
|
|
|
|
This is the easier direction.
|
|
|
|
|
|
|
|
|
|
Rust can expose a conventional C ABI, and Haskell can consume it through its normal FFI mechanisms. That keeps the ownership model and runtime story
|
|
|
|
|
relatively simple, at least compared with the reverse direction.
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
This is the path Garnet takes. It is the better default.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
### Calling Haskell From Rust
|
|
|
|
|
|
|
|
|
|
This is the harder direction.
|
|
|
|
|
|
|
|
|
|
Once Rust starts calling into Haskell, the GHC runtime becomes part of the design. That raises the complexity around runtime initialization,
|
2026-03-24 14:24:30 +01:00
|
|
|
threading, callbacks, shutdown, and operational correctness. It is possible, but it is a worse default.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
Reviewer verdict: call Rust from Haskell when possible; only call Haskell from Rust when there is a strong reason.
|
|
|
|
|
|
|
|
|
|
## Toolchain Recommendation
|
|
|
|
|
|
|
|
|
|
Current best default:
|
|
|
|
|
|
|
|
|
|
- keep the ABI small and C-shaped
|
|
|
|
|
- use Rust `extern "C"` plus `repr(C)` at the boundary
|
|
|
|
|
- use `cbindgen` to emit headers
|
|
|
|
|
- keep Haskell bindings thin
|
|
|
|
|
- write the final Haskell API by hand
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
That is the most credible path today.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
For teams that want the lowest risk, hand-written Haskell FFI bindings are still easier to trust than a large generated surface. For teams exploring
|
2026-03-24 14:24:30 +01:00
|
|
|
automation, `hs-bindgen` is worth watching but is still early-stage technology.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
## Practical Read On Garnet
|
|
|
|
|
|
2026-03-24 14:24:30 +01:00
|
|
|
Garnet is useful because it shows both sides of the story.
|
2026-03-24 09:50:06 +01:00
|
|
|
|
|
|
|
|
It shows that the basic interop path works. It also shows that the surrounding tooling is not yet smooth enough to disappear into the background.
|
2026-03-24 14:24:30 +01:00
|
|
|
It is a useful experiment and a warning about the current workflow cost.
|