2026-02-17 14:57:34 +00:00
|
|
|
module Main (main) where
|
|
|
|
|
|
2026-02-19 11:11:54 +00:00
|
|
|
import Data.ByteString
|
2026-02-19 11:21:38 +00:00
|
|
|
import Data.Word
|
2026-02-19 11:08:20 +00:00
|
|
|
import Foreign.C
|
2026-02-19 11:11:23 +00:00
|
|
|
import GarnetRs
|
2026-02-19 11:08:20 +00:00
|
|
|
import GarnetRs.Safe
|
|
|
|
|
import HsBindgen.Runtime.PtrConst
|
2026-02-19 11:21:38 +00:00
|
|
|
import Unsafe.Coerce
|
Call Rust from Haskell with `cargo-cabal` and `hs-bindgen`
See https://sraka.xyz/posts/hs-bindgen-introduction.html.
For now, this is a shell-based workflow, rather than using Nix to build everything, i.e. `nix develop` works but `nix build` doesn't. And `cargo build` has to be called manually to create the C library, rather than `cabal` being clever enough to invoke it itself.
We ran `cargo cabal init` from the `rust` directory (`nix shell github:yvan-sraka/cargo-cabal`), which generated `hsbindgen.toml` (which we use), and `Setup.lhs` (which just added `extra-lib-dirs`, and with the wrong paths, so we dspecify those statically instead in `garnet.cabal`). We also follow its advice to use `staticlib`.
Also, after we ran the first `cargo build` (requiring a `mkdir rust/src` before it would run), we took the generated the Haskell file, and moved the main contents in to `Main.hs` manually.
2026-02-18 15:49:08 +00:00
|
|
|
|
2026-02-17 14:57:34 +00:00
|
|
|
main :: IO ()
|
2026-02-19 11:08:20 +00:00
|
|
|
main = do
|
2026-02-19 11:11:54 +00:00
|
|
|
useAsCString "Haskell" $ hello . unsafeFromPtr
|
2026-02-19 11:21:38 +00:00
|
|
|
hello_struct $ convertT T'{a = True, b = 42}
|
|
|
|
|
hello_struct $ convertT T'{a = False, b = 42}
|
|
|
|
|
hello_shape $ convertShape $ Circle 3.14
|
|
|
|
|
hello_shape $ convertShape $ Rectangle 10.0 5.0
|
|
|
|
|
|
|
|
|
|
data T' = T'
|
|
|
|
|
{ a :: Bool
|
|
|
|
|
, b :: Word8
|
|
|
|
|
}
|
|
|
|
|
convertT T'{a, b} =
|
|
|
|
|
-- T{a = CBool $ unsafeCoerce @Bool @Word8 a, b}
|
|
|
|
|
T{a = CBool $ fromIntegral $ fromEnum a, b}
|
|
|
|
|
|
|
|
|
|
data Shape'
|
|
|
|
|
= Circle CDouble
|
|
|
|
|
| Rectangle CDouble CDouble
|
|
|
|
|
convertShape = \case
|
|
|
|
|
Circle r -> Shape (Shape_Tag 0) $ set_shape_body_circle $ Circle_Body r
|
|
|
|
|
Rectangle w h -> Shape (Shape_Tag 1) $ set_shape_body_rectangle $ Rectangle_Body w h
|