Compare commits

...

21 Commits

Author SHA1 Message Date
George Thomas
3235165797 debug wip 2026-04-14 01:44:18 +01:00
George Thomas
7a07808115 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:44:18 +01:00
George Thomas
23f732cabf file dependency reload stuff 2026-04-14 01:44:18 +01:00
George Thomas
7105ad0fd5 basic enum example 2026-04-14 01:44:18 +01:00
George Thomas
4f57e96071 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:44:18 +01:00
George Thomas
8f7a1c31f3 Add maybe/optional example 2026-04-14 01:44:18 +01:00
George Thomas
6ec7bc004f Add vector/slice example 2026-04-14 01:44:18 +01:00
George Thomas
97e2fd8823 Remove unnecessary Rust unit return type annotations 2026-04-14 01:44:18 +01:00
George Thomas
09ca0541ca Pass all non-primitive types by (immutable) reference 2026-04-14 01:44:18 +01:00
George Thomas
c3ac431600 Deduplicate base dependency 2026-04-14 01:44:18 +01:00
George Thomas
a69c1a0031 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:44:18 +01:00
George Thomas
2d0b7f26e0 Reformat 2026-04-14 01:44:18 +01:00
George Thomas
0771074981 Remove unnecessary library linking 2026-04-14 01:44:18 +01:00
George Thomas
40f62bf808 Specify include directories via environment variable 2026-04-14 01:44:18 +01:00
George Thomas
358b55c6e1 Minor refactor to avoid long line 2026-04-14 01:43:52 +01:00
George Thomas
c1308094f1 Combine overrides 2026-04-14 01:43:52 +01:00
George Thomas
325cb98b76 Inline project Nix file 2026-04-14 01:43:52 +01:00
George Thomas
9452f9f95a Remove unused binding 2026-04-14 01:41:48 +01:00
George Thomas
4fb40e2ed4 Simplify build script
Seeing as we now no longer need to modify generated header files.
2026-04-14 01:41:48 +01:00
George Thomas
3395fe3b1c Bump hs-bindgen to avoid header patching hack 2026-04-14 01:41:48 +01:00
George Thomas
a35380b3e9 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 _seems_ fine
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
2026-04-14 01:41:48 +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 => {}
}
} }