Compare commits

..

10 Commits

Author SHA1 Message Date
George Thomas
24359a519c more LLVM 2026-02-19 11:34:54 +00:00
George Thomas
aa05650ec8 add LLVM lib 2026-02-19 11:33:13 +00:00
George Thomas
34ce6078ba wip 2026-02-19 11:21:38 +00:00
George Thomas
e53fb108f4 Simplify use sites by passing by value 2026-02-19 11:15:38 +00:00
George Thomas
14ef0237cb Use ByteString 2026-02-19 11:11:54 +00:00
George Thomas
96daf482ca Add more complex data types 2026-02-19 11:11:23 +00:00
George Thomas
ad78170066 Expose explicit C interface 2026-02-19 11:08:20 +00:00
George Thomas
b1d8b6e1bf Move Haskell executable in to subdirectory 2026-02-19 10:57:19 +00:00
George Thomas
7e572b75ee Remove empty other-modules 2026-02-19 10:56:23 +00:00
George Thomas
bc21f9e79f 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-19 10:56:23 +00:00
16 changed files with 130 additions and 192 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
dist* dist*/
result result
target target

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "inputs/real"]
path = inputs/private
url = git@github.com:georgefst/aoc-private-inputs.git

View File

@ -1,4 +1,4 @@
packages: . packages: haskell
-- TODO a total hack -- TODO a total hack
package garnet package garnet
@ -15,7 +15,7 @@ source-repository-package
type: git type: git
location: https://github.com/well-typed/hs-bindgen location: https://github.com/well-typed/hs-bindgen
tag: e2a9260678d9fa76dab602a5a07927acada3be4f tag: e2a9260678d9fa76dab602a5a07927acada3be4f
subdir: c-expr-dsl c-expr-runtime hs-bindgen-runtime subdir: c-expr-dsl c-expr-runtime hs-bindgen hs-bindgen-runtime
--sha256: 0nrs3iq0l5ha5kxyhqnlmvgi7734pmzyp3zf7p8s1gb21ylh4sy0 --sha256: 0nrs3iq0l5ha5kxyhqnlmvgi7734pmzyp3zf7p8s1gb21ylh4sy0
source-repository-package source-repository-package
type: git type: git

View File

@ -1,41 +0,0 @@
-- TODO automate this sort of high level wrapper boilerplate
-- or look at upstream plans: https://github.com/well-typed/hs-bindgen/issues?q=state%3Aopen%20label%3A%22highlevel%22
module GarnetRs.Wrapped (
T (..),
Shape (..),
hello,
helloStruct,
helloShape,
) where
import Data.ByteString
import Data.Word
import Foreign
import Foreign.C
import GarnetRs qualified as Raw
import GarnetRs.Safe qualified as Raw
import HsBindgen.Runtime.PtrConst
data T = T
{ a :: Bool
, b :: Word8
}
convertT :: T -> Raw.T
convertT T{a, b} = Raw.T{a = CBool $ fromBool a, b}
data Shape
= Circle CDouble
| Rectangle CDouble CDouble
convertShape :: Shape -> Raw.Shape
convertShape = \case
Circle r -> Raw.Shape (Raw.Shape_Tag 0) $ Raw.set_shape_body_circle $ Raw.Circle_Body r
Rectangle w h -> Raw.Shape (Raw.Shape_Tag 1) $ Raw.set_shape_body_rectangle $ Raw.Rectangle_Body w h
hello :: ByteString -> IO ()
hello s = useAsCString s $ Raw.hello . unsafeFromPtr
helloStruct :: T -> IO ()
helloStruct = Raw.hello_struct . convertT
helloShape :: Shape -> IO ()
helloShape = Raw.hello_shape . convertShape

View File

@ -1,11 +0,0 @@
module Main (main) where
import GarnetRs.Wrapped
main :: IO ()
main = do
hello "Haskell"
helloStruct T{a = True, b = 42}
helloStruct T{a = False, b = maxBound}
helloShape $ Circle 3.14
helloShape $ Rectangle 10.0 5.0

132
flake.lock generated
View File

@ -85,11 +85,11 @@
}, },
"crane": { "crane": {
"locked": { "locked": {
"lastModified": 1771438068, "lastModified": 1771121070,
"narHash": "sha256-nGBbXvEZVe/egCPVPFcu89RFtd8Rf6J+4RFoVCFec0A=", "narHash": "sha256-aIlv7FRXF9q70DNJPI237dEDAznSKaXmL5lfK/Id/bI=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "b5090e53e9d68c523a4bb9ad42b4737ee6747597", "rev": "a2812c19f1ed2e5ed5ce2ef7109798b575c180e1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -115,24 +115,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@ -154,11 +136,11 @@
"hackage": { "hackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1771461386, "lastModified": 1771289625,
"narHash": "sha256-93hCxhNOq9/HAggfTTurLhllI0IiEWZ35jk6i/X/qEo=", "narHash": "sha256-ySABvJf2NaxGc1mPSkwKjC8So9S906UgOYZVzX35Ng8=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "hackage.nix", "repo": "hackage.nix",
"rev": "b4f4537825a4db29c10541a50d7eb6c848bf0dca", "rev": "808af568b7e14e1eced115e65825d2f50a608008",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -170,11 +152,11 @@
"hackage-for-stackage": { "hackage-for-stackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1771461376, "lastModified": 1771288450,
"narHash": "sha256-aEuZkBpTaU0XBFiaIomicJDoWQaw84rYfKXI/r17V/w=", "narHash": "sha256-2tCS6CXMHPo4Jsh4JopbYBoQXnTTp8MdZVAqPVmOIq4=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "hackage.nix", "repo": "hackage.nix",
"rev": "ca611068e77f15b96ecf71fae827e491c0b2dc3b", "rev": "3049efd880816a3bb98b7b5fb4062045fcddd474",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -200,7 +182,7 @@
"type": "github" "type": "github"
} }
}, },
"haskell-nix": { "haskellNix": {
"inputs": { "inputs": {
"HTTP": "HTTP", "HTTP": "HTTP",
"cabal-32": "cabal-32", "cabal-32": "cabal-32",
@ -228,7 +210,7 @@
"hpc-coveralls": "hpc-coveralls", "hpc-coveralls": "hpc-coveralls",
"iserv-proxy": "iserv-proxy", "iserv-proxy": "iserv-proxy",
"nixpkgs": [ "nixpkgs": [
"haskell-nix", "haskellNix",
"nixpkgs-unstable" "nixpkgs-unstable"
], ],
"nixpkgs-2305": "nixpkgs-2305", "nixpkgs-2305": "nixpkgs-2305",
@ -242,11 +224,11 @@
"stackage": "stackage" "stackage": "stackage"
}, },
"locked": { "locked": {
"lastModified": 1771462666, "lastModified": 1771289806,
"narHash": "sha256-z+pJFzbYa1ulNDUZdb0qLVVAdE0dqpnE51jqh2chA7c=", "narHash": "sha256-s60Kb3cYr0t6LDQ/LmJr5vQN8Z4IY1Vfwq2keZW0VOM=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "haskell.nix", "repo": "haskell.nix",
"rev": "857ba7b65d9c1a8765ad1599834a8fe71cb09981", "rev": "3331ba591ae02a41c638aeb6bea91d268b34cf8e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -525,27 +507,6 @@
"type": "github" "type": "github"
} }
}, },
"hs-bindgen": {
"inputs": {
"flake-parts": "flake-parts",
"libclang-bindings-src": "libclang-bindings-src",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1770394582,
"narHash": "sha256-erbj5xqqJ/M0c99G0vjZvJtvoxYJ1PG7DDkw15MVLK8=",
"owner": "well-typed",
"repo": "hs-bindgen",
"rev": "e2a9260678d9fa76dab602a5a07927acada3be4f",
"type": "github"
},
"original": {
"owner": "well-typed",
"ref": "release-0.1-alpha",
"repo": "hs-bindgen",
"type": "github"
}
},
"iserv-proxy": { "iserv-proxy": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -563,39 +524,6 @@
"type": "github" "type": "github"
} }
}, },
"libclang-bindings-src": {
"flake": false,
"locked": {
"lastModified": 1770274896,
"narHash": "sha256-JnxJBo2L4URFD8JbpjnPG/ej/xKFe7y5ZpjnvIztwAM=",
"owner": "well-typed",
"repo": "libclang",
"rev": "155642a4a4a9f0414a058a8f08f39aa6c7bb57ed",
"type": "github"
},
"original": {
"owner": "well-typed",
"repo": "libclang",
"rev": "155642a4a4a9f0414a058a8f08f39aa6c7bb57ed",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1770169770,
"narHash": "sha256-awR8qIwJxJJiOmcEGgP2KUqYmHG4v/z8XpL9z8FnT1A=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "aa290c9891fa4ebe88f8889e59633d20cc06a5f2",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2305": { "nixpkgs-2305": {
"locked": { "locked": {
"lastModified": 1705033721, "lastModified": 1705033721,
@ -692,21 +620,6 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-lib": {
"locked": {
"lastModified": 1769909678,
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "72716169fe93074c333e8d0173151350670b824c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1764587062, "lastModified": 1764587062,
@ -744,11 +657,10 @@
"inputs": { "inputs": {
"crane": "crane", "crane": "crane",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"haskell-nix": "haskell-nix", "haskellNix": "haskellNix",
"hls-2-13": "hls-2-13", "hls-2-13": "hls-2-13",
"hs-bindgen": "hs-bindgen",
"nixpkgs": [ "nixpkgs": [
"haskell-nix", "haskellNix",
"nixpkgs-2511" "nixpkgs-2511"
], ],
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
@ -761,11 +673,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1771470520, "lastModified": 1771297684,
"narHash": "sha256-PvytHcaYN5cPUll7FB70mXv1rRsIBRmu47fFfq3haxA=", "narHash": "sha256-wieWskQxZLPlNXX06JEB0bMoS/ZYQ89xBzF0RL9lyLs=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "a1d4cc1f264c45d3745af0d2ca5e59d460e58777", "rev": "755d3669699a7c62aef35af187d75dc2728cfd85",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -777,11 +689,11 @@
"stackage": { "stackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1771460325, "lastModified": 1771287554,
"narHash": "sha256-RRsGO7QVyuBtUTVqDiB7CYvFruj0Z/yxZK1JarkTqI4=", "narHash": "sha256-76Kd5c2D4O8yL48eAejlGZlpQ/Exxnsz3V7qW+RkFzE=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "stackage.nix", "repo": "stackage.nix",
"rev": "29c0dcc517e04be238023064412312ad4443ddb2", "rev": "e62b9d6269c6abfd8b976826da0dcc37f0a57010",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -1,22 +1,28 @@
{ {
inputs = { inputs = {
haskell-nix.url = "github:input-output-hk/haskell.nix"; haskellNix.url = "github:input-output-hk/haskell.nix";
hls-2-13 = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; }; hls-2-13 = { url = "github:haskell/haskell-language-server/2.13.0.0"; flake = false; };
nixpkgs.follows = "haskell-nix/nixpkgs-2511"; nixpkgs.follows = "haskellNix/nixpkgs-2511";
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 = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
hs-bindgen.url = "github:well-typed/hs-bindgen/release-0.1-alpha";
}; };
outputs = outputs =
inputs@{ nixpkgs, ... }: { self
inputs.flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: , nixpkgs
, flake-utils
, haskellNix
, hls-2-13
, crane
, rust-overlay
}:
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let let
overlays = [ overlays = [
inputs.haskell-nix.overlay haskellNix.overlay
(final: _prev: { (final: _prev: {
hixProject = hixProject =
final.haskell-nix.hix.project { final.haskell-nix.hix.project {
@ -27,18 +33,20 @@
shell.tools.cabal = "latest"; shell.tools.cabal = "latest";
shell.withHoogle = false; shell.withHoogle = false;
shell.tools.haskell-language-server = { shell.tools.haskell-language-server = {
src = inputs.hls-2-13; src = hls-2-13;
sha256map = { sha256map = {
"https://github.com/snowleopard/alga"."d4e43fb42db05413459fb2df493361d5a666588a" = "0s1mlnl64wj7pkg3iipv5bb4syy3bhxwqzqv93zqlvkyfn64015i"; "https://github.com/snowleopard/alga"."d4e43fb42db05413459fb2df493361d5a666588a" = "0s1mlnl64wj7pkg3iipv5bb4syy3bhxwqzqv93zqlvkyfn64015i";
}; };
}; };
}; };
}) })
(import inputs.rust-overlay) (import rust-overlay)
]; ];
pkgs = import nixpkgs { inherit system overlays; inherit (inputs.haskell-nix) config; }; pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; };
haskell = pkgs.hixProject.flake { }; haskell = pkgs.hixProject.flake { };
rust = (inputs.crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith ( # TODO we're not getting Rust libs from Nix
# i.e. running `cargo clean && cargo build` rebuilds dependencies
rust = (crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith (
toolchain: toolchain.default.override { toolchain: toolchain.default.override {
extensions = [ "rust-src" ]; extensions = [ "rust-src" ];
targets = [ "x86_64-unknown-linux-gnu" ]; targets = [ "x86_64-unknown-linux-gnu" ];
@ -52,12 +60,13 @@
(rust.devShell { }) (rust.devShell { })
]; ];
packages = with pkgs; [ packages = with pkgs; [
llvmPackages.libclang
llvmPackages.llvm
bacon bacon
ghcid ghcid
inputs.hs-bindgen.packages.${system}.hs-bindgen-cli
rust-analyzer rust-analyzer
rust-cbindgen
]; ];
}; };
}); }
);
} }

View File

@ -3,15 +3,23 @@ set -euo pipefail
# TODO this is a complete vibe-coded hack, but the header patching at least is crucial # TODO this is a complete vibe-coded hack, but the header patching at least is crucial
# TODO fully-vibed hack
# we should do a few things quite differently anyway
# generated Haskell code shouldn't be checked in as it's not portable
# does the TH way of using `hs-bindgen` help here?
# I guess we shouldn't check in the generated C header either
# Generate Haskell FFI bindings from Rust source code. # Generate Haskell FFI bindings from Rust source code.
# #
# Pipeline: cargo build -> cbindgen -> patch header -> hs-bindgen # Pipeline: cargo build -> cbindgen -> patch header -> hs-bindgen
# #
# Prerequisites: run inside the Nix dev shell (provides gcc, cabal, cbindgen, hs-bindgen-cli). # Prerequisites: run inside the Nix dev shell (provides gcc, cabal, etc.)
# cbindgen is fetched via `nix run nixpkgs#rust-cbindgen`.
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
RUST_DIR="$SCRIPT_DIR/rust" RUST_DIR="$SCRIPT_DIR/rust"
HASKELL_DIR="$SCRIPT_DIR" HASKELL_DIR="$SCRIPT_DIR/haskell"
HEADER_NAME="garnet_rs.h" HEADER_NAME="garnet_rs.h"
HEADER="$RUST_DIR/$HEADER_NAME" HEADER="$RUST_DIR/$HEADER_NAME"
@ -21,7 +29,7 @@ cargo build --manifest-path "$RUST_DIR/Cargo.toml"
# --- Step 2: Generate C header with cbindgen --- # --- Step 2: Generate C header with cbindgen ---
echo "=== Running cbindgen ===" echo "=== Running cbindgen ==="
cbindgen \ nix run nixpkgs#rust-cbindgen -- \
--lang c \ --lang c \
--crate garnet-rs \ --crate garnet-rs \
--output "$HEADER" \ --output "$HEADER" \
@ -89,7 +97,8 @@ pending_enum && /^typedef [A-Za-z0-9_]+ / {
} }
{ print } { print }
' "$HEADER" > "${HEADER}.tmp" && mv "${HEADER}.tmp" "$HEADER" ' "$HEADER" > "${HEADER}.tmp"
mv "${HEADER}.tmp" "$HEADER"
echo " Patched header at $HEADER" echo " Patched header at $HEADER"
@ -115,7 +124,7 @@ fi
# --- Step 5: Run hs-bindgen --- # --- Step 5: Run hs-bindgen ---
echo "=== Running hs-bindgen ===" echo "=== Running hs-bindgen ==="
hs-bindgen-cli preprocess \ cabal run -- hs-bindgen-cli preprocess \
--overwrite-files --create-output-dirs \ --overwrite-files --create-output-dirs \
--unique-id com.garnet --enable-record-dot \ --unique-id com.garnet --enable-record-dot \
--hs-output-dir "$HASKELL_DIR/generated" --module GarnetRs \ --hs-output-dir "$HASKELL_DIR/generated" --module GarnetRs \
@ -124,4 +133,4 @@ hs-bindgen-cli preprocess \
echo "=== Done ===" echo "=== Done ==="
echo "Generated Haskell bindings in $HASKELL_DIR/generated/" echo "Generated Haskell bindings in $HASKELL_DIR/generated/"
echo "Run 'cabal run' to test." echo "Run 'cabal run garnet' to test."

30
haskell/LICENSE Normal file
View File

@ -0,0 +1,30 @@
Copyright (c) 2025, George Thomas
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of George Thomas nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

32
haskell/exe/Main.hs Normal file
View File

@ -0,0 +1,32 @@
module Main (main) where
import Data.ByteString
import Data.Word
import Foreign.C
import GarnetRs
import GarnetRs.Safe
import HsBindgen.Runtime.PtrConst
import Unsafe.Coerce
main :: IO ()
main = do
useAsCString "Haskell" $ hello . unsafeFromPtr
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

View File

@ -1,11 +1,9 @@
cabal-version: 3.0 cabal-version: 3.0
name: garnet name: garnet
version: 0.1.0.0 version: 0.1.0.0
license: BSD-3-Clause license-file: LICENSE
author: Patrick Aldis author: Patrick Aldis
maintainer: maintainer: patricktaldis@gmail.com
george.thomas@obsidian.systems
patrick.aldis@obsidian.systems
library garnet-generated library garnet-generated
hs-source-dirs: generated hs-source-dirs: generated
@ -23,8 +21,6 @@ library garnet-generated
executable garnet executable garnet
main-is: Main.hs main-is: Main.hs
other-modules:
GarnetRs.Wrapped
hs-source-dirs: exe hs-source-dirs: exe
default-language: GHC2024 default-language: GHC2024
default-extensions: default-extensions:

View File

@ -1,5 +1,3 @@
#![allow(dead_code)]
use std::ffi::{CStr, c_char}; use std::ffi::{CStr, c_char};
fn say_hello(name: &str) { fn say_hello(name: &str) {
@ -23,6 +21,7 @@ extern "C" fn hello_struct(t: T) -> () {
} }
#[repr(C, u8)] #[repr(C, u8)]
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
enum Shape { enum Shape {
Circle { radius: f64 }, Circle { radius: f64 },