Compare commits

...

21 Commits

Author SHA1 Message Date
George Thomas
346e558e0a debug wip 2026-04-14 01:46:24 +01:00
George Thomas
ce742e4763 bump to hs-bindgen and libclang to latest...
had hoped this might solve the weird field naming but alas - should just report issue
2026-04-14 01:46:24 +01:00
George Thomas
15187cd760 file dependency reload stuff 2026-04-14 01:46:24 +01:00
George Thomas
16f75fef9b basic enum example 2026-04-14 01:46:24 +01:00
George Thomas
2d2d29b7a5 Use lambdas in all wrappers for consistency
This is partly with a view to eventually abstracting away much of the boilerplate.
2026-04-14 01:46:24 +01:00
George Thomas
8ec85e8192 Add maybe/optional example 2026-04-14 01:46:24 +01:00
George Thomas
d9ae85e18c Add vector/slice example 2026-04-14 01:46:24 +01:00
George Thomas
51b23f6b38 Remove unnecessary Rust unit return type annotations 2026-04-14 01:46:24 +01:00
George Thomas
adc542fd21 Pass all non-primitive types by (immutable) reference 2026-04-14 01:46:24 +01:00
George Thomas
6430724da3 Deduplicate base dependency 2026-04-14 01:46:24 +01:00
George Thomas
89cbbcb2e8 Get Rust Analyzer from overlay instead of directly from Nixpkgs
Right now, the latter invokes `cargo metadata --lockfile-path`,
which this Cargo nightly doesn't support.
2026-04-14 01:46:24 +01:00
George Thomas
96049682b2 Reformat 2026-04-14 01:46:24 +01:00
George Thomas
b01f37791f Remove unnecessary library linking 2026-04-14 01:46:24 +01:00
George Thomas
b8eb0d01b7 Specify include directories via environment variable 2026-04-14 01:46:24 +01:00
George Thomas
4c9a9e4ef2 Minor refactor to avoid long line 2026-04-14 01:46:24 +01:00
George Thomas
58f3aa80b6 Combine overrides 2026-04-14 01:46:24 +01:00
George Thomas
759d375a49 Inline project Nix file 2026-04-14 01:46:24 +01:00
George Thomas
80afc3b9d4 Remove unused binding 2026-04-14 01:46:24 +01:00
George Thomas
ec6af8133b Simplify build script
Seeing as we now no longer need to modify generated header files.
2026-04-14 01:46:24 +01:00
George Thomas
53142f902e Bump hs-bindgen to avoid header patching hack 2026-04-14 01:46:24 +01:00
George Thomas
d3cee99e92 stuff from Yuri
things I've changed from the PR:
- dropped legacy (i.e. non-flake) compat stuff, which turns out to account for most of the diff
- dropped `packages.garnet` since it doesn't work with `nix build .#garnet`
- back to using Rust-extended packages everywhere, which isn't very important but seems fine anyway
the rest is just re-inlining things and other refactors

final question:
it does seems a bit weird that `garnet-rs` arg to `project.nix` was always the same
might be a mistake, and we're supposed to be using local for local build?

"improve nix-haskell use"

there are a few things going on here but the main ones are ...
note that changes we keep are essentially:
- bumping `nix-haskell` to avoid shell hook workaround
- various changes in how we call `nix-haskell`
- using `libCgarnet_rs` name, which Cabal expects
- adding proper non-dev-shell targets, so that e.g. `nix run` works

should add co-author attribution
2026-04-14 01:45:35 +01:00
10 changed files with 891 additions and 147 deletions

4
build
View File

@ -1,10 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# generate this file from Nix config for now to avoid duplication?
cargo build --manifest-path ./rust/Cargo.toml cargo build --manifest-path ./rust/Cargo.toml
BUNDLED_LIB_DIR=$(cabal list-bin . | sed -e 's=x/garnet/build/garnet/garnet=build=g') BUNDLED_LIB_DIR=$(cabal list-bin . | sed -e 's=x/garnet/build/garnet/garnet=build=g')
mkdir -p $BUNDLED_LIB_DIR mkdir -p $BUNDLED_LIB_DIR
ln -sf $(pwd)/rust/target/debug/libgarnet_rs.a $BUNDLED_LIB_DIR ln -sf $(pwd)/rust/target/debug/libgarnet_rs.a $BUNDLED_LIB_DIR/libCgarnet_rs.a
cabal build cabal build

View File

@ -1,13 +1,20 @@
module Main (main) where module Main (main) where
import Data.Vector.Storable qualified as V
import GarnetRs.Wrapped import GarnetRs.Wrapped
import System.IO
main :: IO () main :: IO ()
main = do main = do
hello "Haskell" hello "Haskell"
helloStruct T{a = True, b = 42} helloStruct T{a = True, b = 42}
helloStruct T{a = False, b = maxBound} helloStruct T{a = False, b = maxBound}
helloEnum E1
helloEnum E3
helloShape $ Circle 3.14 helloShape $ Circle 3.14
helloShape $ Rectangle 10.0 5.0 helloShape $ Rectangle 10.0 5.0
putStrLn $ "3 + 4 = " <> show (add 3 4) putStrLn $ "3 + 4 = " <> show (add 3 4)
putStrLn $ "Tree sum: " <> show (sumTree (Fork (Fork (Leaf 1) (Fork (Leaf 2) (Leaf 3))) (Leaf 4))) putStrLn $ "Tree sum: " <> show (sumTree (Fork (Fork (Leaf 1) (Fork (Leaf 2) (Leaf 3))) (Leaf 4)))
putStrLn $ "Slice sum: " <> show (sumSlice $ V.fromList [0 .. 5])
putStrLn "Nothing." >> printOptional Nothing
putStr "Something: " >> hFlush stdout >> printOptional (Just 67)

707
flake.lock generated
View File

@ -1,12 +1,95 @@
{ {
"nodes": { "nodes": {
"HTTP": {
"flake": false,
"locked": {
"lastModified": 1451647621,
"narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=",
"owner": "phadej",
"repo": "HTTP",
"rev": "9bc0996d412fef1787449d841277ef663ad9a915",
"type": "github"
},
"original": {
"owner": "phadej",
"repo": "HTTP",
"type": "github"
}
},
"cabal-32": {
"flake": false,
"locked": {
"lastModified": 1603716527,
"narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=",
"owner": "haskell",
"repo": "cabal",
"rev": "48bf10787e27364730dd37a42b603cee8d6af7ee",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.2",
"repo": "cabal",
"type": "github"
}
},
"cabal-34": {
"flake": false,
"locked": {
"lastModified": 1645834128,
"narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=",
"owner": "haskell",
"repo": "cabal",
"rev": "5ff598c67f53f7c4f48e31d722ba37172230c462",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.4",
"repo": "cabal",
"type": "github"
}
},
"cabal-36": {
"flake": false,
"locked": {
"lastModified": 1669081697,
"narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=",
"owner": "haskell",
"repo": "cabal",
"rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.6",
"repo": "cabal",
"type": "github"
}
},
"cardano-shell": {
"flake": false,
"locked": {
"lastModified": 1608537748,
"narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=",
"owner": "input-output-hk",
"repo": "cardano-shell",
"rev": "9392c75087cb9a3d453998f4230930dea3a95725",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "cardano-shell",
"type": "github"
}
},
"crane": { "crane": {
"locked": { "locked": {
"lastModified": 1771438068, "lastModified": 1774313767,
"narHash": "sha256-nGBbXvEZVe/egCPVPFcu89RFtd8Rf6J+4RFoVCFec0A=", "narHash": "sha256-hy0XTQND6avzGEUFrJtYBBpFa/POiiaGBr2vpU6Y9tY=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "b5090e53e9d68c523a4bb9ad42b4737ee6747597", "rev": "3d9df76e29656c679c744968b17fbaf28f0e923d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -15,6 +98,38 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1672831974,
"narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=",
"owner": "input-output-hk",
"repo": "flake-compat",
"rev": "45f2638735f8cdc40fe302742b79f248d23eb368",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "hkm/gitlab-fix",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@ -33,6 +148,349 @@
"type": "github" "type": "github"
} }
}, },
"hackage": {
"flake": false,
"locked": {
"lastModified": 1770685064,
"narHash": "sha256-e2G/GFzIdTXosxq+3Z0OXbSUmXy9tDbZZ6wsmfy7Hf8=",
"owner": "input-output-hk",
"repo": "hackage.nix",
"rev": "84628a8e4b5d580766d49d62a5e2e065cbb8604e",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "hackage.nix",
"type": "github"
}
},
"hackage-for-stackage": {
"flake": false,
"locked": {
"lastModified": 1770683900,
"narHash": "sha256-03cshwLY80e5jBUgNBmoFoiH1e3VvhAX+1ME4NVt5g4=",
"owner": "input-output-hk",
"repo": "hackage.nix",
"rev": "c7d9e737cd1e07136982e0df0f9aa12391e2c883",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "for-stackage",
"repo": "hackage.nix",
"type": "github"
}
},
"hackage-internal": {
"flake": false,
"locked": {
"lastModified": 1750307553,
"narHash": "sha256-iiafNoeLHwlSLQTyvy8nPe2t6g5AV4PPcpMeH/2/DLs=",
"owner": "input-output-hk",
"repo": "hackage.nix",
"rev": "f7867baa8817fab296528f4a4ec39d1c7c4da4f3",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "hackage.nix",
"type": "github"
}
},
"haskell-nix": {
"inputs": {
"HTTP": "HTTP",
"cabal-32": "cabal-32",
"cabal-34": "cabal-34",
"cabal-36": "cabal-36",
"cardano-shell": "cardano-shell",
"flake-compat": "flake-compat_2",
"hackage": "hackage",
"hackage-for-stackage": "hackage-for-stackage",
"hackage-internal": "hackage-internal",
"hls": "hls",
"hls-1.10": "hls-1.10",
"hls-2.0": "hls-2.0",
"hls-2.10": "hls-2.10",
"hls-2.11": "hls-2.11",
"hls-2.12": "hls-2.12",
"hls-2.2": "hls-2.2",
"hls-2.3": "hls-2.3",
"hls-2.4": "hls-2.4",
"hls-2.5": "hls-2.5",
"hls-2.6": "hls-2.6",
"hls-2.7": "hls-2.7",
"hls-2.8": "hls-2.8",
"hls-2.9": "hls-2.9",
"hpc-coveralls": "hpc-coveralls",
"iserv-proxy": "iserv-proxy",
"nixpkgs": [
"nix-haskell",
"haskell-nix",
"nixpkgs-unstable"
],
"nixpkgs-2305": "nixpkgs-2305",
"nixpkgs-2311": "nixpkgs-2311",
"nixpkgs-2405": "nixpkgs-2405",
"nixpkgs-2411": "nixpkgs-2411",
"nixpkgs-2505": "nixpkgs-2505",
"nixpkgs-2511": "nixpkgs-2511",
"nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix",
"stackage": "stackage"
},
"locked": {
"lastModified": 1773942398,
"narHash": "sha256-VFUyPaWqXN357StToBRFbOCZAP4n8iCfEh2ZV1dNH88=",
"owner": "ymeister",
"repo": "haskell.nix",
"rev": "9fa7c11202e16c8cd2743deed4d811da1cfb2e51",
"type": "github"
},
"original": {
"owner": "ymeister",
"repo": "haskell.nix",
"rev": "9fa7c11202e16c8cd2743deed4d811da1cfb2e51",
"type": "github"
}
},
"hls": {
"flake": false,
"locked": {
"lastModified": 1741604408,
"narHash": "sha256-tuq3+Ip70yu89GswZ7DSINBpwRprnWnl6xDYnS4GOsc=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "682d6894c94087da5e566771f25311c47e145359",
"type": "github"
},
"original": {
"owner": "haskell",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-1.10": {
"flake": false,
"locked": {
"lastModified": 1680000865,
"narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "1.10.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.0": {
"flake": false,
"locked": {
"lastModified": 1687698105,
"narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "783905f211ac63edf982dd1889c671653327e441",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.0.0.1",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.10": {
"flake": false,
"locked": {
"lastModified": 1743069404,
"narHash": "sha256-q4kDFyJDDeoGqfEtrZRx4iqMVEC2MOzCToWsFY+TOzY=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "2318c61db3a01e03700bd4b05665662929b7fe8b",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.10.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.11": {
"flake": false,
"locked": {
"lastModified": 1747306193,
"narHash": "sha256-/MmtpF8+FyQlwfKHqHK05BdsxC9LHV70d/FiMM7pzBM=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "46ef4523ea4949f47f6d2752476239f1c6d806fe",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.11.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.12": {
"flake": false,
"locked": {
"lastModified": 1758709460,
"narHash": "sha256-xkI8MIIVEVARskfWbGAgP5sHG/lyeKnkm0LIOJ19X5w=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "7d983de4fa7ff54369f6dd31444bdb9869aec83e",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.12.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.2": {
"flake": false,
"locked": {
"lastModified": 1693064058,
"narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.2.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.3": {
"flake": false,
"locked": {
"lastModified": 1695910642,
"narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.3.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.4": {
"flake": false,
"locked": {
"lastModified": 1699862708,
"narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.4.0.1",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.5": {
"flake": false,
"locked": {
"lastModified": 1701080174,
"narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "27f8c3d3892e38edaef5bea3870161815c4d014c",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.5.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.6": {
"flake": false,
"locked": {
"lastModified": 1705325287,
"narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.6.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.7": {
"flake": false,
"locked": {
"lastModified": 1708965829,
"narHash": "sha256-LfJ+TBcBFq/XKoiNI7pc4VoHg4WmuzsFxYJ3Fu+Jf+M=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "50322b0a4aefb27adc5ec42f5055aaa8f8e38001",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.7.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.8": {
"flake": false,
"locked": {
"lastModified": 1715153580,
"narHash": "sha256-Vi/iUt2pWyUJlo9VrYgTcbRviWE0cFO6rmGi9rmALw0=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "dd1be1beb16700de59e0d6801957290bcf956a0a",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.8.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.9": {
"flake": false,
"locked": {
"lastModified": 1719993701,
"narHash": "sha256-wy348++MiMm/xwtI9M3vVpqj2qfGgnDcZIGXw8sF1sA=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "90319a7e62ab93ab65a95f8f2bcf537e34dae76a",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.9.0.1",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-src": { "hls-src": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -50,50 +508,84 @@
"type": "github" "type": "github"
} }
}, },
"hpc-coveralls": {
"flake": false,
"locked": {
"lastModified": 1607498076,
"narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=",
"owner": "sevanspowell",
"repo": "hpc-coveralls",
"rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430",
"type": "github"
},
"original": {
"owner": "sevanspowell",
"repo": "hpc-coveralls",
"type": "github"
}
},
"hs-bindgen-src": { "hs-bindgen-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773399083, "lastModified": 1776078838,
"narHash": "sha256-oF6E1/zRZ4iiZs9QjtQMvHnLMfq/W6CXOX44QbDGYXs=", "narHash": "sha256-f8SE6IuACy8bzIX+EOYTpekaAI/TOQ3zTwJKJmHl3LY=",
"owner": "well-typed", "owner": "well-typed",
"repo": "hs-bindgen", "repo": "hs-bindgen",
"rev": "6ca94188abd756a1fb4dd8a4037de3fa7dca0765", "rev": "ca714aca1ed941271ac248488c9a469554c5b470",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "well-typed", "owner": "well-typed",
"repo": "hs-bindgen", "repo": "hs-bindgen",
"rev": "6ca94188abd756a1fb4dd8a4037de3fa7dca0765", "type": "github"
}
},
"iserv-proxy": {
"flake": false,
"locked": {
"lastModified": 1770174258,
"narHash": "sha256-x6QYupvHZM7rRpVO4AIC5gUWFprFQ59A95FPC7/Owjg=",
"owner": "stable-haskell",
"repo": "iserv-proxy",
"rev": "91ef7ffdeedfb141a4d69dcf9e550abe3e1160c6",
"type": "github"
},
"original": {
"owner": "stable-haskell",
"ref": "iserv-syms",
"repo": "iserv-proxy",
"type": "github" "type": "github"
} }
}, },
"libclang-src": { "libclang-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773221966, "lastModified": 1775645278,
"narHash": "sha256-VPG7jKdq2g/Hwf5cPiy4coAvLULxDeA4KHCVkNSSs5w=", "narHash": "sha256-JWARcbqH432vWcCvQ2bagTXBka8sCRNAnK1qOmnLWKw=",
"owner": "well-typed", "owner": "well-typed",
"repo": "libclang", "repo": "libclang",
"rev": "d6e482df49b88375cf3075928a78ee86c2a068d4", "rev": "bf574efcb492d2738d8a82b6ce556f840ff92778",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "well-typed", "owner": "well-typed",
"repo": "libclang", "repo": "libclang",
"rev": "d6e482df49b88375cf3075928a78ee86c2a068d4",
"type": "github" "type": "github"
} }
}, },
"nix-haskell": { "nix-haskell": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs" "flake-compat": "flake-compat",
"haskell-nix": "haskell-nix",
"nixpkgs": "nixpkgs",
"reflex-platform": "reflex-platform"
}, },
"locked": { "locked": {
"lastModified": 1774311314, "lastModified": 1774408168,
"narHash": "sha256-sxoNFlpTaBnnQerzQ2LTByXPpR37M4pHnhZmzq+9440=", "narHash": "sha256-do26Ik50yH8NYSxuhwzBwNKsxIN88GoovwioWPvCpJU=",
"owner": "reflex-frp", "owner": "reflex-frp",
"repo": "nix-haskell", "repo": "nix-haskell",
"rev": "85d89f1cc2f591ff6be35e1f112c8ee912fba7bb", "rev": "d6a3bb8f96ff35fd0ae2a0d64f40b584c92aa493",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -104,16 +596,164 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1773840656, "lastModified": 1769089682,
"narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=", "narHash": "sha256-9yA/LIuAVQq0lXelrZPjLuLVuZdm03p8tfmHhnDIkms=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512", "rev": "078d69f03934859a181e81ba987c2bb033eebfc5",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "NixOS",
"type": "indirect" "repo": "nixpkgs",
"rev": "078d69f03934859a181e81ba987c2bb033eebfc5",
"type": "github"
}
},
"nixpkgs-2305": {
"locked": {
"lastModified": 1705033721,
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-23.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2311": {
"locked": {
"lastModified": 1719957072,
"narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7144d6241f02d171d25fba3edeaf15e0f2592105",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-23.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2405": {
"locked": {
"lastModified": 1735564410,
"narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-24.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2411": {
"locked": {
"lastModified": 1751290243,
"narHash": "sha256-kNf+obkpJZWar7HZymXZbW+Rlk3HTEIMlpc6FCNz0Ds=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5ab036a8d97cb9476fbe81b09076e6e91d15e1b6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-24.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2505": {
"locked": {
"lastModified": 1764560356,
"narHash": "sha256-M5aFEFPppI4UhdOxwdmceJ9bDJC4T6C6CzCK1E2FZyo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-25.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2511": {
"locked": {
"lastModified": 1764572236,
"narHash": "sha256-hLp6T/vKdrBQolpbN3EhJOKTXZYxJZPzpnoZz+fEGlE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b0924ea1889b366de6bb0018a9db70b2c43a15f8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-25.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1764587062,
"narHash": "sha256-hdFa0TAVQAQLDF31cEW3enWmBP+b592OvHs6WVe3D8k=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c1cb7d097cb250f6e1904aacd5f2ba5ffd8a49ce",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"old-ghc-nix": {
"flake": false,
"locked": {
"lastModified": 1631092763,
"narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=",
"owner": "angerman",
"repo": "old-ghc-nix",
"rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8",
"type": "github"
},
"original": {
"owner": "angerman",
"ref": "master",
"repo": "old-ghc-nix",
"type": "github"
}
},
"reflex-platform": {
"flake": false,
"locked": {
"lastModified": 1760924715,
"narHash": "sha256-pUraGts8qa3R9jQqaVXevkC+nM07B8oF+LGF4xsyiJU=",
"owner": "reflex-frp",
"repo": "reflex-platform",
"rev": "4482ecb04c5939ac77c26d769d149dee12051a13",
"type": "github"
},
"original": {
"owner": "reflex-frp",
"repo": "reflex-platform",
"rev": "4482ecb04c5939ac77c26d769d149dee12051a13",
"type": "github"
} }
}, },
"root": { "root": {
@ -124,22 +764,25 @@
"hs-bindgen-src": "hs-bindgen-src", "hs-bindgen-src": "hs-bindgen-src",
"libclang-src": "libclang-src", "libclang-src": "libclang-src",
"nix-haskell": "nix-haskell", "nix-haskell": "nix-haskell",
"nixpkgs": [
"nix-haskell",
"nixpkgs"
],
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
} }
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nix-haskell",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1771470520, "lastModified": 1774408260,
"narHash": "sha256-PvytHcaYN5cPUll7FB70mXv1rRsIBRmu47fFfq3haxA=", "narHash": "sha256-Jn9d9r85dmf3gTMnSRt6t+DP2nQ5uJns/MMXg2FpzfM=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "a1d4cc1f264c45d3745af0d2ca5e59d460e58777", "rev": "d6471ee5a8f470251e6e5b83a20a182eb6c46c9b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -148,6 +791,22 @@
"type": "github" "type": "github"
} }
}, },
"stackage": {
"flake": false,
"locked": {
"lastModified": 1770596307,
"narHash": "sha256-88b6YzeBaQr9ihSWAOxVGewCDfROKt2rOIHymadu3DI=",
"owner": "input-output-hk",
"repo": "stackage.nix",
"rev": "ff21e9b6a976faed56963ae5fa5d5396dc48ea63",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "stackage.nix",
"type": "github"
}
},
"systems": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,

View File

@ -1,43 +1,108 @@
{ {
inputs = { inputs = {
nix-haskell.url = "github:reflex-frp/nix-haskell"; nix-haskell.url = "github:reflex-frp/nix-haskell";
nixpkgs.follows = "nix-haskell/nixpkgs";
hls-src = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; }; hls-src = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; };
hs-bindgen-src = { url = "github:well-typed/hs-bindgen/6ca94188abd756a1fb4dd8a4037de3fa7dca0765"; flake = false; }; hs-bindgen-src = { url = "github:well-typed/hs-bindgen"; flake = false; };
libclang-src = { url = "github:well-typed/libclang/d6e482df49b88375cf3075928a78ee86c2a068d4"; flake = false; }; libclang-src = { url = "github:well-typed/libclang"; flake = false; };
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
crane.url = "github:ipetkov/crane"; crane.url = "github:ipetkov/crane";
rust-overlay = { rust-overlay = {
url = "github:oxalica/rust-overlay"; url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nix-haskell/nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = outputs =
inputs@{ nix-haskell, ... }: inputs:
inputs.flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: inputs.flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let let
lib = nix-haskell.lib.${system}; pkgs = haskell.nixpkgs.extend (import inputs.rust-overlay);
project = lib.nix-haskell (import ./project.nix { inherit (inputs) hls-src hs-bindgen-src libclang-src; }); crane = (inputs.crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith (
haskell = project.haskell-nix.project;
pkgs = project.nixpkgs.extend (import inputs.rust-overlay);
rust = (inputs.crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith (
toolchain: toolchain.default.override { toolchain: toolchain.default.override {
extensions = [ "rust-src" ]; extensions = [ "rust-src" "rust-analyzer" ];
targets = [ "x86_64-unknown-linux-gnu" ]; targets = [ "x86_64-unknown-linux-gnu" ];
} }
)); ));
addLibcIncludeDir =
''
export C_INCLUDE_PATH="${pkgs.stdenv.cc.libc.dev}/include''${C_INCLUDE_PATH:+:$C_INCLUDE_PATH}"
'';
haskell = (import inputs.nix-haskell { inherit system inputs; } {
name = "garnet";
src = ./.;
compiler-nix-name = "ghc914";
source-repository-packages = {
# not on Hackage yet: https://well-typed.com/blog/2026/02/hs-bindgen-alpha
# we're using more recent versions than in that post, because we want record-dot support:
# https://github.com/well-typed/hs-bindgen/issues/1829#issuecomment-4081875451
c-expr-dsl = inputs.hs-bindgen-src + "/c-expr-dsl";
c-expr-runtime = inputs.hs-bindgen-src + "/c-expr-runtime";
hs-bindgen = inputs.hs-bindgen-src + "/hs-bindgen";
hs-bindgen-runtime = inputs.hs-bindgen-src + "/hs-bindgen-runtime";
libclang-bindings = inputs.libclang-src;
};
overrides = [
({ pkgs, ... }: {
packages.libclang-bindings.components.library = {
build-tools = [ pkgs.llvmPackages.llvm ];
libs = [ pkgs.llvmPackages.libclang ];
};
packages.garnet.components.library = {
preBuild = addLibcIncludeDir;
# try removing?
preConfigure = ''
mkdir -p rust/target/debug
ln -s ${garnet-rs}/include/garnet_rs.h rust/target/debug/garnet_rs.h
'';
preInstall = ''
cp ${garnet-rs}/lib/libCgarnet_rs.a dist/build/libCgarnet_rs.a
'';
configureFlags = [ "--extra-lib-dirs=${garnet-rs}/lib" ];
};
})
];
shell = {
tools = {
cabal = "latest";
haskell-language-server = {
src = inputs.hls-src;
sha256map = {
"https://github.com/snowleopard/alga" = {
"d4e43fb42db05413459fb2df493361d5a666588a" = "0s1mlnl64wj7pkg3iipv5bb4syy3bhxwqzqv93zqlvkyfn64015i";
};
};
};
};
withHoogle = false;
withHaddock = true;
shellHook = addLibcIncludeDir;
};
});
garnet-rs = crane.buildPackage {
src = crane.cleanCargoSource ./rust;
doCheck = false;
installPhaseCommand = ''
mkdir -p $out/lib $out/include
cp target/release/libgarnet_rs.a $out/lib/libCgarnet_rs.a
cp target/release/garnet_rs.h $out/include/
'';
};
in in
{ rec {
defaultPackage = packages.garnet-exe;
packages = let garnet = haskell.project.haskell-nix.hsPkgs.garnet; in {
inherit garnet-rs;
garnet-exe = garnet.components.exes.garnet;
garnet-lib = garnet.components.library;
};
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
inputsFrom = [ inputsFrom = [
(haskell.shell.overrideAttrs (old: { haskell.project.haskell-nix.shell
shellHook = builtins.replaceStrings [ "*wasm*|)" ] [ "*wasm*)" ] old.shellHook; (crane.devShell { })
}))
(rust.devShell { })
]; ];
packages = with pkgs; [ packages = with pkgs; [
bacon bacon
ghcid ghcid
rust-analyzer
]; ];
}; };
}); });

View File

@ -6,6 +6,21 @@ author: Patrick Aldis
maintainer: maintainer:
george.thomas@obsidian.systems george.thomas@obsidian.systems
patrick.aldis@obsidian.systems patrick.aldis@obsidian.systems
-- aha, nice, this does fix recompilation checking
extra-source-files:
rust/target/debug/garnet_rs.h
-- that could be problematic given file is gitignored? unfortunately this doesn't work
-- tbf, I haven't even looked up the docs, just saw the autocompletion
-- extra-tmp-files:
-- rust/target/debug/garnet_rs.h
-- actually maybe this is pointless given we always need debug path anyway in `extra-source-files`
-- plus we have it in `Raw.hs`
flag dev
default:
False
manual:
True
common common common common
default-language: GHC2024 default-language: GHC2024
@ -22,17 +37,20 @@ common common
NoMonomorphismRestriction NoMonomorphismRestriction
OverloadedRecordDot OverloadedRecordDot
OverloadedStrings OverloadedStrings
PatternSynonyms
RecordWildCards RecordWildCards
ViewPatterns ViewPatterns
ghc-options: ghc-options:
-Wall -Wall
-fdefer-type-errors -fdefer-type-errors
build-depends: build-depends:
base,
bytestring, bytestring,
extra, extra,
mtl, mtl,
process, process,
text, text,
vector,
library library
import: common import: common
@ -40,13 +58,16 @@ library
GarnetRs.Raw GarnetRs.Raw
GarnetRs.Wrapped GarnetRs.Wrapped
hs-source-dirs: lib hs-source-dirs: lib
-- if flag (dev)
-- include-dirs: rust/target/debug
include-dirs: rust/target/debug include-dirs: rust/target/debug
extra-bundled-libraries: garnet_rs -- HLS gives up entirely when the header is malformed if we do this
-- and anyway, I don't think it gives us dependency tracking like `extra-source-files` does
-- includes: garnet_rs.h
extra-bundled-libraries: Cgarnet_rs
build-depends: build-depends:
base,
hs-bindgen, hs-bindgen,
hs-bindgen-runtime, hs-bindgen-runtime,
primitive,
template-haskell, template-haskell,
executable garnet executable garnet
@ -58,5 +79,4 @@ executable garnet
-rtsopts -rtsopts
-with-rtsopts=-N -with-rtsopts=-N
build-depends: build-depends:
base,
garnet, garnet,

View File

@ -1,6 +1,5 @@
{-# LANGUAGE CApiFFI #-} {-# LANGUAGE CApiFFI #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FieldSelectors #-}
{-# LANGUAGE MagicHash #-} {-# LANGUAGE MagicHash #-}
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
@ -30,19 +29,10 @@ import HsBindgen.TH
import Language.Haskell.TH import Language.Haskell.TH
import System.Process import System.Process
do
systemDirs <- -- TODO bit of a hack
map (Dir . T.unpack . T.strip)
. concatMap (takeWhile (maybe False ((== ' ') . fst) . T.uncons) . dropWhile T.null . T.lines)
. drop 1
. T.splitOn "search starts here:"
. T.pack
. thd3
<$> runIO (readProcessWithExitCode "cpp" ["-v"] "")
withHsBindgen withHsBindgen
def def
{ clang = def{extraIncludeDirs = Pkg "rust/target/debug" : systemDirs} { clang = def{extraIncludeDirs = [Pkg "rust/target/debug"]}
, fieldNamingStrategy = EnableRecordDot , fieldNamingStrategy = OmitFieldPrefixes
} }
def def
$ hashInclude "garnet_rs.h" $ hashInclude "garnet_rs.h"

View File

@ -2,19 +2,29 @@
-- or look at upstream plans: https://github.com/well-typed/hs-bindgen/issues?q=state%3Aopen%20label%3A%22highlevel%22 -- or look at upstream plans: https://github.com/well-typed/hs-bindgen/issues?q=state%3Aopen%20label%3A%22highlevel%22
module GarnetRs.Wrapped ( module GarnetRs.Wrapped (
T (..), T (..),
Raw.E (..),
-- TODO hmm, we don't really want to have to list all of these...
-- is there an option to make them not be patterns at all?
pattern Raw.E1,
pattern Raw.E2,
pattern Raw.E3,
Shape (..), Shape (..),
BTree (..), BTree (..),
hello, hello,
helloStruct, helloStruct,
helloEnum,
helloShape, helloShape,
add, add,
sumTree, sumTree,
sumSlice,
printOptional,
) where ) where
import Control.Monad.Cont import Control.Monad.Cont
import Control.Monad.Trans import Control.Monad.Trans
import Data.ByteString import Data.ByteString
import Data.Function import Data.Function
import Data.Vector.Storable qualified as V
import Data.Word import Data.Word
import Foreign import Foreign
import Foreign.C import Foreign.C
@ -34,8 +44,8 @@ data Shape
| Rectangle CDouble CDouble | Rectangle CDouble CDouble
convertShape :: Shape -> Raw.Shape convertShape :: Shape -> Raw.Shape
convertShape = \case convertShape = \case
Circle r -> Raw.Shape Raw.Circle $ Raw.set_shape_body_circle $ Raw.Circle_Body r Circle r -> Raw.Shape Raw.Circle $ Raw.set_shape_circle_circle $ Raw.Circle_Body r
Rectangle w h -> Raw.Shape Raw.Rectangle $ Raw.set_shape_body_rectangle $ Raw.Rectangle_Body w h Rectangle w h -> Raw.Shape Raw.Rectangle $ Raw.set_shape_circle_rectangle $ Raw.Rectangle_Body w h
data BTree a data BTree a
= Leaf a = Leaf a
@ -43,27 +53,38 @@ data BTree a
withBTree :: BTree Int64 -> (Raw.BTreeC -> IO a) -> IO a withBTree :: BTree Int64 -> (Raw.BTreeC -> IO a) -> IO a
withBTree = withBTree =
runContT . fix \f -> \case runContT . fix \f -> \case
Leaf v -> pure $ Raw.BTreeC Raw.Leaf $ Raw.set_bTreeC_body_leaf $ Raw.Leaf_Body v Leaf v -> pure $ Raw.BTreeC Raw.Leaf $ Raw.set_bTreeC_leaf_leaf $ Raw.Leaf_Body v
Fork l r -> do Fork l r -> do
lRaw <- f l lRaw <- f l
rRaw <- f r rRaw <- f r
lPtr <- ContT alloca lPtr <- ContT alloca
rPtr <- ContT alloca rPtr <- ContT alloca
lift $ poke lPtr lRaw >> poke rPtr rRaw lift $ poke lPtr lRaw >> poke rPtr rRaw
pure . Raw.BTreeC Raw.Fork . Raw.set_bTreeC_body_fork $ pure . Raw.BTreeC Raw.Fork . Raw.set_bTreeC_leaf_fork $
Raw.Fork_Body (unsafeFromPtr lPtr) (unsafeFromPtr rPtr) Raw.Fork_Body (unsafeFromPtr lPtr) (unsafeFromPtr rPtr)
hello :: ByteString -> IO () hello :: ByteString -> IO ()
hello s = useAsCString s $ Raw.hello . unsafeFromPtr hello bs = useAsCString bs \ptr -> Raw.hello $ unsafeFromPtr ptr
helloStruct :: T -> IO () helloStruct :: T -> IO ()
helloStruct = Raw.hello_struct . convertT helloStruct t = with (convertT t) \ptr -> Raw.hello_struct $ unsafeFromPtr ptr
helloEnum :: Raw.E -> IO ()
helloEnum e = with e \ptr -> Raw.hello_enum $ unsafeFromPtr ptr
helloShape :: Shape -> IO () helloShape :: Shape -> IO ()
helloShape = Raw.hello_shape . convertShape helloShape s = with (convertShape s) \ptr -> Raw.hello_shape $ unsafeFromPtr ptr
add :: Int64 -> Int64 -> Int64 add :: Int64 -> Int64 -> Int64
add = Raw.add add = Raw.add
sumTree :: BTree Int64 -> Int64 sumTree :: BTree Int64 -> Int64
sumTree = unsafePerformIO . flip withBTree Raw.sum_tree sumTree t = unsafePerformIO $ withBTree t \tc -> with tc \ptr -> Raw.sum_tree $ unsafeFromPtr ptr
sumSlice :: V.Vector Int64 -> Int64
sumSlice v = unsafePerformIO $ V.unsafeWith v \ptr -> Raw.sum_slice (unsafeFromPtr ptr) (fromIntegral $ V.length v)
printOptional :: Maybe Int8 -> IO ()
printOptional = \case
Nothing -> Raw.print_optional $ unsafeFromPtr nullPtr
Just t -> with t \ptr -> Raw.print_optional $ unsafeFromPtr ptr

View File

@ -1,40 +0,0 @@
{ hls-src
, hs-bindgen-src
, libclang-src
}:
{
name = "garnet";
src = ./.;
compiler-nix-name = "ghc914";
source-repository-packages = {
# not on Hackage yet: https://well-typed.com/blog/2026/02/hs-bindgen-alpha
# we're using more recent versions than in that post, because we want record-dot support:
# https://github.com/well-typed/hs-bindgen/issues/1829#issuecomment-4081875451
c-expr-dsl = hs-bindgen-src + "/c-expr-dsl";
c-expr-runtime = hs-bindgen-src + "/c-expr-runtime";
hs-bindgen = hs-bindgen-src + "/hs-bindgen";
hs-bindgen-runtime = hs-bindgen-src + "/hs-bindgen-runtime";
libclang-bindings = libclang-src;
};
overrides = [
({ pkgs, ... }: {
packages.libclang-bindings.components.library = {
build-tools = [ pkgs.llvmPackages.llvm ];
libs = [ pkgs.llvmPackages.libclang ];
};
})
];
shell = {
tools = {
cabal = "latest";
haskell-language-server = {
src = hls-src;
sha256map = {
"https://github.com/snowleopard/alga"."d4e43fb42db05413459fb2df493361d5a666588a" = "0s1mlnl64wj7pkg3iipv5bb4syy3bhxwqzqv93zqlvkyfn64015i";
};
};
};
withHoogle = false;
withHaddock = true;
};
}

View File

@ -1,43 +1,36 @@
use std::env; use std::env;
use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
fn main() { fn main() {
// this doesn't make _much_ difference really, since this is our only Rust source file
// but it seems it's probably better than not having it
// what we really want is to tell Rust to only regenerate the header file if the Rust code actually compiles
// but we don't have that flexibility
// and it's an issue because cbindgen tries to be fault-tolerant in some ways that don't even seem to make sense
//
// e.g. mis-spell "Option" as "Option" and you get
// void print_optional(Optio<const int8_t*> x);
// instead of
// void print_optional(const int8_t *x);
// and that's only an issue because in HLS TH dependent-file watching gives up after an error
// i.e. once the containing splice has thrown an exception once, the containing file needs a manual edit to kick it
// and that's really not helped by Rust Analyzer mostly only showing diagnostics on save
// P.S. strings to stdout?! what a terrible API
// don't get me started in the discoverability of actually then using the terminal for debugging:
// println!("cargo::warning={:?}", env::var("OUT_DIR"));
println!("cargo::rerun-if-changed=lib.rs");
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let profile = env::var("PROFILE").unwrap(); let profile = env::var("PROFILE").unwrap();
cbindgen::Builder::new()
let bindings = cbindgen::Builder::new()
.with_crate(&crate_dir) .with_crate(&crate_dir)
.with_language(cbindgen::Language::C) .with_language(cbindgen::Language::C)
.with_style(cbindgen::Style::Tag) .with_style(cbindgen::Style::Tag)
.generate() .generate()
.expect("Unable to generate bindings"); .expect("Unable to generate bindings")
.write_to_file(
// TODO vibe-coded workaround for hs-bindgen issue:
// https://github.com/well-typed/hs-bindgen/issues/1649#issuecomment-3994425922
let mut buf = Vec::new();
bindings.write(&mut buf);
let header = String::from_utf8(buf).unwrap();
let mut patched = String::new();
let mut saw_union = false;
for line in header.lines() {
if line == " };" && saw_union {
patched.push_str(" } body;\n");
saw_union = false;
continue;
}
if line == " union {" {
saw_union = true;
}
patched.push_str(line);
patched.push('\n');
}
fs::write(
PathBuf::from(&crate_dir) PathBuf::from(&crate_dir)
.join("target") .join("target")
.join(&profile) .join(&profile)
.join("garnet_rs.h"), .join("garnet_rs.h"),
patched, );
)
.unwrap();
} }

View File

@ -3,6 +3,7 @@
use std::{ use std::{
ffi::{CStr, c_char}, ffi::{CStr, c_char},
ops::Add, ops::Add,
slice,
}; };
fn say_hello(name: &str) { fn say_hello(name: &str) {
@ -10,7 +11,7 @@ fn say_hello(name: &str) {
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn hello(c: *const c_char) -> () { extern "C" fn hello(c: *const c_char) {
say_hello(unsafe { CStr::from_ptr(c) }.to_str().unwrap()) say_hello(unsafe { CStr::from_ptr(c) }.to_str().unwrap())
} }
@ -22,10 +23,23 @@ struct T {
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn hello_struct(t: T) -> () { extern "C" fn hello_struct(t: &T) {
say_hello(&format!("{:?}", t)) say_hello(&format!("{:?}", t))
} }
#[repr(C)]
#[derive(Debug)]
enum E {
E1,
E2,
E3,
}
#[unsafe(no_mangle)]
extern "C" fn hello_enum(e: &E) {
say_hello(&format!("{:?}", e))
}
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
enum Shape { enum Shape {
@ -34,7 +48,7 @@ enum Shape {
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn hello_shape(s: Shape) -> () { extern "C" fn hello_shape(s: &Shape) {
say_hello(&format!("{:?}", s)) say_hello(&format!("{:?}", s))
} }
@ -78,6 +92,19 @@ enum BTreeC {
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn sum_tree(t: BTreeC) -> i64 { extern "C" fn sum_tree(t: &BTreeC) -> i64 {
(unsafe { std::mem::transmute::<_, &BTree<i64>>(&t) }).sum() (unsafe { std::mem::transmute::<_, &BTree<i64>>(t) }).sum()
}
#[unsafe(no_mangle)]
extern "C" fn sum_slice(v: *const i64, s: usize) -> i64 {
unsafe { slice::from_raw_parts(v, s) }.iter().sum()
}
#[unsafe(no_mangle)]
extern "C" fn print_optional(x: Option<&i8>) -> () {
match x {
Some(x) => println!("{}", x / 2),
None => {}
}
} }