Compare commits

..

No commits in common. "e53fb108f41224f469116a6c31f128b01d664e9e" and "39283930d52a3276c39aa55e6f3c5559f0a1e21b" have entirely different histories.

15 changed files with 23 additions and 1072 deletions

View File

@ -1,28 +1,5 @@
packages: haskell packages: haskell
-- TODO a total hack
package garnet
extra-lib-dirs:
/home/gthomas/code/garnet/rust/target/release
/home/gthomas/code/garnet/rust/target/debug
extra-include-dirs:
/home/gthomas/code/garnet/rust
-- https://well-typed.com/blog/2026/02/hs-bindgen-alpha
-- Haskell.nix doesn't seem to like `tag: release-0.1-alpha`, which the blog post suggests
-- so we specify the equivalent commit SHAs manually instead
source-repository-package
type: git
location: https://github.com/well-typed/hs-bindgen
tag: e2a9260678d9fa76dab602a5a07927acada3be4f
subdir: c-expr-dsl c-expr-runtime hs-bindgen hs-bindgen-runtime
--sha256: 0nrs3iq0l5ha5kxyhqnlmvgi7734pmzyp3zf7p8s1gb21ylh4sy0
source-repository-package
type: git
location: https://github.com/well-typed/libclang
tag: b5ff712c91c039cde6720ffe2096a121d9f4d802
--sha256: 1lwjdxd2ahhkvyxrpli7z9z7ss4l94m2jaif8kg1i2yygbhksrb3
allow-newer: allow-newer:
*:base, *:base,
*:containers, *:containers,

View File

@ -44,8 +44,6 @@
]; ];
pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; }; pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; };
haskell = pkgs.hixProject.flake { }; haskell = pkgs.hixProject.flake { };
# 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 ( rust = (crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith (
toolchain: toolchain.default.override { toolchain: toolchain.default.override {
extensions = [ "rust-src" ]; extensions = [ "rust-src" ];
@ -65,6 +63,10 @@
rust-analyzer rust-analyzer
]; ];
}; };
packages = {
haskell = haskell.packages."garnet:exe:garnet";
rust = rust.buildPackage { src = rust.cleanCargoSource ./rust; };
};
} }
); );
} }

View File

@ -1,128 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# TODO this is a complete vibe-coded hack, but the header patching at least is crucial
# Generate Haskell FFI bindings from Rust source code.
#
# Pipeline: cargo build -> cbindgen -> patch header -> hs-bindgen
#
# 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)"
RUST_DIR="$SCRIPT_DIR/rust"
HASKELL_DIR="$SCRIPT_DIR/haskell"
HEADER_NAME="garnet_rs.h"
HEADER="$RUST_DIR/$HEADER_NAME"
# --- Step 1: Build Rust static library ---
echo "=== Building Rust library ==="
cargo build --manifest-path "$RUST_DIR/Cargo.toml"
# --- Step 2: Generate C header with cbindgen ---
echo "=== Running cbindgen ==="
nix run nixpkgs#rust-cbindgen -- \
--lang c \
--crate garnet-rs \
--output "$HEADER" \
"$RUST_DIR"
echo " Raw header written to $HEADER"
# --- Step 3: Patch the header for hs-bindgen compatibility ---
echo "=== Patching header ==="
# Two patches are needed:
#
# Patch 1: Replace cbindgen's enum pattern with typedef + #defines.
# cbindgen emits: enum Shape_Tag { Circle, Rectangle, }; typedef uint8_t Shape_Tag;
# hs-bindgen needs: typedef uint8_t Shape_Tag; #define Circle 0 ...
#
# Patch 2: Name anonymous unions inside structs.
# cbindgen emits: union { ... };
# hs-bindgen needs: union { ... } body;
awk '
# State machine for enum->typedef+define transformation
/^enum [A-Za-z_][A-Za-z0-9_]* \{$/ {
in_enum = 1
enum_name = $2
variant_count = 0
delete variants
next
}
in_enum && /^\};$/ {
# Next line should be: typedef <type> <enum_name>;
in_enum = 0
pending_enum = 1
next
}
in_enum {
# Collect variant names (strip trailing comma and whitespace)
v = $0
gsub(/^[[:space:]]+/, "", v)
gsub(/,[[:space:]]*$/, "", v)
if (v != "") {
variants[variant_count] = v
variant_count++
}
next
}
pending_enum && /^typedef [A-Za-z0-9_]+ / {
# Emit: typedef <type> <name>; then #define for each variant
print $0
for (i = 0; i < variant_count; i++) {
printf "#define %s %d\n", variants[i], i
}
pending_enum = 0
next
}
# Name anonymous unions: }; at end of union block inside struct -> } body;
/^ \};$/ && saw_union {
print " } body;"
saw_union = 0
next
}
/^ union \{$/ {
saw_union = 1
}
{ print }
' "$HEADER" > "${HEADER}.tmp" && mv "${HEADER}.tmp" "$HEADER"
echo " Patched header at $HEADER"
# --- Step 4: Derive system include paths for hs-bindgen's libclang ---
echo "=== Detecting system include paths ==="
# hs-bindgen uses libclang directly, which doesn't know about NixOS's
# non-standard include locations. We extract them from cpp -v and pass
# all of them — extra paths are harmless.
CLANG_OPTIONS=()
while IFS= read -r dir; do
CLANG_OPTIONS+=("--clang-option" "-isystem$dir")
done < <(echo | cpp -v 2>&1 | awk '/#include <\.\.\.> search starts here:/{f=1;next}/End of search list/{f=0}f{gsub(/^ +/,"");print}')
if [ ${#CLANG_OPTIONS[@]} -eq 0 ]; then
echo " WARNING: No system include paths detected. hs-bindgen may fail."
else
echo " Found ${#CLANG_OPTIONS[@]} clang options:"
for ((i=0; i<${#CLANG_OPTIONS[@]}; i+=2)); do
echo " ${CLANG_OPTIONS[i+1]}"
done
fi
# --- Step 5: Run hs-bindgen ---
echo "=== Running hs-bindgen ==="
cabal run -- hs-bindgen-cli preprocess \
--overwrite-files --create-output-dirs \
--unique-id com.garnet --enable-record-dot \
--hs-output-dir "$HASKELL_DIR/generated" --module GarnetRs \
"${CLANG_OPTIONS[@]}" \
-I "$RUST_DIR" "$HEADER_NAME"
echo "=== Done ==="
echo "Generated Haskell bindings in $HASKELL_DIR/generated/"
echo "Run 'cabal run garnet' to test."

5
haskell/Main.hs Normal file
View File

@ -0,0 +1,5 @@
module Main (main) where
main :: IO ()
main = do
putStrLn "Hello from Haskell"

View File

@ -1,14 +0,0 @@
module Main (main) where
import Data.ByteString
import Foreign.C
import GarnetRs
import GarnetRs.Safe
import HsBindgen.Runtime.PtrConst
main :: IO ()
main = do
useAsCString "Haskell" $ hello . unsafeFromPtr
hello_struct T{a = CBool 1, b = 42}
hello_shape $ Shape (Shape_Tag 0) $ set_shape_body_circle $ Circle_Body 3.14
hello_shape $ Shape (Shape_Tag 1) $ set_shape_body_rectangle $ Rectangle_Body 10.0 5.0

View File

@ -5,23 +5,10 @@ license-file: LICENSE
author: Patrick Aldis author: Patrick Aldis
maintainer: patricktaldis@gmail.com maintainer: patricktaldis@gmail.com
library garnet-generated
hs-source-dirs: generated
exposed-modules:
GarnetRs
GarnetRs.Safe
GarnetRs.Unsafe
GarnetRs.FunPtr
default-language: Haskell2010
extra-bundled-libraries: garnet_rs
build-depends:
base,
hs-bindgen-runtime,
primitive,
executable garnet executable garnet
main-is: Main.hs main-is: Main.hs
hs-source-dirs: exe hs-source-dirs: .
other-modules:
default-language: GHC2024 default-language: GHC2024
default-extensions: default-extensions:
BlockArguments BlockArguments
@ -46,6 +33,3 @@ executable garnet
-with-rtsopts=-N -with-rtsopts=-N
build-depends: build-depends:
base >= 4.14, base >= 4.14,
bytestring,
garnet-generated,
hs-bindgen-runtime,

View File

@ -1,476 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}
module GarnetRs where
import qualified Data.Array.Byte
import qualified Data.Bits as Bits
import qualified Data.Ix as Ix
import qualified Data.Primitive.Types
import qualified Data.Proxy
import qualified Foreign as F
import qualified Foreign.C as FC
import qualified GHC.Generics
import qualified GHC.Ptr as Ptr
import qualified GHC.Records
import qualified HsBindgen.Runtime.HasCField
import qualified HsBindgen.Runtime.Internal.Bitfield
import qualified HsBindgen.Runtime.Internal.ByteArray
import qualified HsBindgen.Runtime.Internal.HasFFIType
import qualified HsBindgen.Runtime.Internal.SizedByteArray
import qualified HsBindgen.Runtime.LibC
import qualified HsBindgen.Runtime.Marshal
import Data.Bits (FiniteBits)
import HsBindgen.Runtime.Internal.TypeEquality (TyEq)
import Prelude ((<*>), (>>), Bounded, Enum, Eq, Int, Integral, Num, Ord, Read, Real, Show, pure)
{-| __C declaration:__ @struct T@
__defined at:__ @garnet_rs.h 6:16@
__exported by:__ @garnet_rs.h@
-}
data T = T
{ a :: FC.CBool
{- ^ __C declaration:__ @a@
__defined at:__ @garnet_rs.h 7:8@
__exported by:__ @garnet_rs.h@
-}
, b :: HsBindgen.Runtime.LibC.Word8
{- ^ __C declaration:__ @b@
__defined at:__ @garnet_rs.h 8:11@
__exported by:__ @garnet_rs.h@
-}
}
deriving stock (GHC.Generics.Generic)
deriving stock (Eq, Show)
instance HsBindgen.Runtime.Marshal.StaticSize T where
staticSizeOf = \_ -> (2 :: Int)
staticAlignment = \_ -> (1 :: Int)
instance HsBindgen.Runtime.Marshal.ReadRaw T where
readRaw =
\ptr0 ->
pure T
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"a") ptr0
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"b") ptr0
instance HsBindgen.Runtime.Marshal.WriteRaw T where
writeRaw =
\ptr0 ->
\s1 ->
case s1 of
T a2 b3 ->
HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"a") ptr0 a2
>> HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"b") ptr0 b3
deriving via HsBindgen.Runtime.Marshal.EquivStorable T instance F.Storable T
instance HsBindgen.Runtime.HasCField.HasCField T "a" where
type CFieldType T "a" = FC.CBool
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType T) "a")
) => GHC.Records.HasField "a" (Ptr.Ptr T) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"a")
instance HsBindgen.Runtime.HasCField.HasCField T "b" where
type CFieldType T "b" = HsBindgen.Runtime.LibC.Word8
offset# = \_ -> \_ -> 1
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType T) "b")
) => GHC.Records.HasField "b" (Ptr.Ptr T) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"b")
{-| __C declaration:__ @Shape_Tag@
__defined at:__ @garnet_rs.h 11:17@
__exported by:__ @garnet_rs.h@
-}
newtype Shape_Tag = Shape_Tag
{ unwrap :: HsBindgen.Runtime.LibC.Word8
}
deriving stock (GHC.Generics.Generic)
deriving stock (Eq, Ord, Read, Show)
deriving newtype
( HsBindgen.Runtime.Marshal.StaticSize
, HsBindgen.Runtime.Marshal.ReadRaw
, HsBindgen.Runtime.Marshal.WriteRaw
, F.Storable
, HsBindgen.Runtime.Internal.HasFFIType.HasFFIType
, Data.Primitive.Types.Prim
, HsBindgen.Runtime.Internal.Bitfield.Bitfield
, Bits.Bits
, Bounded
, Enum
, FiniteBits
, Integral
, Ix.Ix
, Num
, Real
)
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Shape_Tag) "unwrap")
) => GHC.Records.HasField "unwrap" (Ptr.Ptr Shape_Tag) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"unwrap")
instance HsBindgen.Runtime.HasCField.HasCField Shape_Tag "unwrap" where
type CFieldType Shape_Tag "unwrap" =
HsBindgen.Runtime.LibC.Word8
offset# = \_ -> \_ -> 0
{-| __C declaration:__ @Circle@
__defined at:__ @garnet_rs.h 12:9@
__exported by:__ @garnet_rs.h@
-}
circle :: FC.CInt
circle = (0 :: FC.CInt)
{-| __C declaration:__ @Rectangle@
__defined at:__ @garnet_rs.h 13:9@
__exported by:__ @garnet_rs.h@
-}
rectangle :: FC.CInt
rectangle = (1 :: FC.CInt)
{-| __C declaration:__ @struct Circle_Body@
__defined at:__ @garnet_rs.h 15:16@
__exported by:__ @garnet_rs.h@
-}
data Circle_Body = Circle_Body
{ radius :: FC.CDouble
{- ^ __C declaration:__ @radius@
__defined at:__ @garnet_rs.h 16:10@
__exported by:__ @garnet_rs.h@
-}
}
deriving stock (GHC.Generics.Generic)
deriving stock (Eq, Show)
instance HsBindgen.Runtime.Marshal.StaticSize Circle_Body where
staticSizeOf = \_ -> (8 :: Int)
staticAlignment = \_ -> (8 :: Int)
instance HsBindgen.Runtime.Marshal.ReadRaw Circle_Body where
readRaw =
\ptr0 ->
pure Circle_Body
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"radius") ptr0
instance HsBindgen.Runtime.Marshal.WriteRaw Circle_Body where
writeRaw =
\ptr0 ->
\s1 ->
case s1 of
Circle_Body radius2 ->
HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"radius") ptr0 radius2
deriving via HsBindgen.Runtime.Marshal.EquivStorable Circle_Body instance F.Storable Circle_Body
instance HsBindgen.Runtime.HasCField.HasCField Circle_Body "radius" where
type CFieldType Circle_Body "radius" = FC.CDouble
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Circle_Body) "radius")
) => GHC.Records.HasField "radius" (Ptr.Ptr Circle_Body) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"radius")
{-| __C declaration:__ @struct Rectangle_Body@
__defined at:__ @garnet_rs.h 19:16@
__exported by:__ @garnet_rs.h@
-}
data Rectangle_Body = Rectangle_Body
{ width :: FC.CDouble
{- ^ __C declaration:__ @width@
__defined at:__ @garnet_rs.h 20:10@
__exported by:__ @garnet_rs.h@
-}
, height :: FC.CDouble
{- ^ __C declaration:__ @height@
__defined at:__ @garnet_rs.h 21:10@
__exported by:__ @garnet_rs.h@
-}
}
deriving stock (GHC.Generics.Generic)
deriving stock (Eq, Show)
instance HsBindgen.Runtime.Marshal.StaticSize Rectangle_Body where
staticSizeOf = \_ -> (16 :: Int)
staticAlignment = \_ -> (8 :: Int)
instance HsBindgen.Runtime.Marshal.ReadRaw Rectangle_Body where
readRaw =
\ptr0 ->
pure Rectangle_Body
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"width") ptr0
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"height") ptr0
instance HsBindgen.Runtime.Marshal.WriteRaw Rectangle_Body where
writeRaw =
\ptr0 ->
\s1 ->
case s1 of
Rectangle_Body width2 height3 ->
HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"width") ptr0 width2
>> HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"height") ptr0 height3
deriving via HsBindgen.Runtime.Marshal.EquivStorable Rectangle_Body instance F.Storable Rectangle_Body
instance HsBindgen.Runtime.HasCField.HasCField Rectangle_Body "width" where
type CFieldType Rectangle_Body "width" = FC.CDouble
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Rectangle_Body) "width")
) => GHC.Records.HasField "width" (Ptr.Ptr Rectangle_Body) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"width")
instance HsBindgen.Runtime.HasCField.HasCField Rectangle_Body "height" where
type CFieldType Rectangle_Body "height" = FC.CDouble
offset# = \_ -> \_ -> 8
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Rectangle_Body) "height")
) => GHC.Records.HasField "height" (Ptr.Ptr Rectangle_Body) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"height")
{-| __C declaration:__ @union \@Shape_body@
__defined at:__ @garnet_rs.h 26:3@
__exported by:__ @garnet_rs.h@
-}
newtype Shape_body = Shape_body
{ unwrap :: Data.Array.Byte.ByteArray
}
deriving stock (GHC.Generics.Generic)
deriving via (HsBindgen.Runtime.Internal.SizedByteArray.SizedByteArray 16) 8 instance HsBindgen.Runtime.Marshal.StaticSize Shape_body
deriving via (HsBindgen.Runtime.Internal.SizedByteArray.SizedByteArray 16) 8 instance HsBindgen.Runtime.Marshal.ReadRaw Shape_body
deriving via (HsBindgen.Runtime.Internal.SizedByteArray.SizedByteArray 16) 8 instance HsBindgen.Runtime.Marshal.WriteRaw Shape_body
deriving via HsBindgen.Runtime.Marshal.EquivStorable Shape_body instance F.Storable Shape_body
{-|
__See:__ 'set_shape_body_circle'
__C declaration:__ @circle@
__defined at:__ @garnet_rs.h 27:17@
__exported by:__ @garnet_rs.h@
-}
get_shape_body_circle ::
Shape_body
-> Circle_Body
get_shape_body_circle =
HsBindgen.Runtime.Internal.ByteArray.getUnionPayload
{-|
__See:__ 'get_shape_body_circle'
-}
set_shape_body_circle ::
Circle_Body
-> Shape_body
set_shape_body_circle =
HsBindgen.Runtime.Internal.ByteArray.setUnionPayload
{-|
__See:__ 'set_shape_body_rectangle'
__C declaration:__ @rectangle@
__defined at:__ @garnet_rs.h 28:20@
__exported by:__ @garnet_rs.h@
-}
get_shape_body_rectangle ::
Shape_body
-> Rectangle_Body
get_shape_body_rectangle =
HsBindgen.Runtime.Internal.ByteArray.getUnionPayload
{-|
__See:__ 'get_shape_body_rectangle'
-}
set_shape_body_rectangle ::
Rectangle_Body
-> Shape_body
set_shape_body_rectangle =
HsBindgen.Runtime.Internal.ByteArray.setUnionPayload
instance HsBindgen.Runtime.HasCField.HasCField Shape_body "circle" where
type CFieldType Shape_body "circle" = Circle_Body
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Shape_body) "circle")
) => GHC.Records.HasField "circle" (Ptr.Ptr Shape_body) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"circle")
instance HsBindgen.Runtime.HasCField.HasCField Shape_body "rectangle" where
type CFieldType Shape_body "rectangle" =
Rectangle_Body
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Shape_body) "rectangle")
) => GHC.Records.HasField "rectangle" (Ptr.Ptr Shape_body) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"rectangle")
{-| __C declaration:__ @struct Shape@
__defined at:__ @garnet_rs.h 24:16@
__exported by:__ @garnet_rs.h@
-}
data Shape = Shape
{ tag :: Shape_Tag
{- ^ __C declaration:__ @tag@
__defined at:__ @garnet_rs.h 25:13@
__exported by:__ @garnet_rs.h@
-}
, body :: Shape_body
{- ^ __C declaration:__ @body@
__defined at:__ @garnet_rs.h 29:5@
__exported by:__ @garnet_rs.h@
-}
}
deriving stock (GHC.Generics.Generic)
instance HsBindgen.Runtime.Marshal.StaticSize Shape where
staticSizeOf = \_ -> (24 :: Int)
staticAlignment = \_ -> (8 :: Int)
instance HsBindgen.Runtime.Marshal.ReadRaw Shape where
readRaw =
\ptr0 ->
pure Shape
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"tag") ptr0
<*> HsBindgen.Runtime.HasCField.readRaw (Data.Proxy.Proxy @"body") ptr0
instance HsBindgen.Runtime.Marshal.WriteRaw Shape where
writeRaw =
\ptr0 ->
\s1 ->
case s1 of
Shape tag2 body3 ->
HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"tag") ptr0 tag2
>> HsBindgen.Runtime.HasCField.writeRaw (Data.Proxy.Proxy @"body") ptr0 body3
deriving via HsBindgen.Runtime.Marshal.EquivStorable Shape instance F.Storable Shape
instance HsBindgen.Runtime.HasCField.HasCField Shape "tag" where
type CFieldType Shape "tag" = Shape_Tag
offset# = \_ -> \_ -> 0
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Shape) "tag")
) => GHC.Records.HasField "tag" (Ptr.Ptr Shape) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"tag")
instance HsBindgen.Runtime.HasCField.HasCField Shape "body" where
type CFieldType Shape "body" = Shape_body
offset# = \_ -> \_ -> 8
instance ( TyEq ty ((HsBindgen.Runtime.HasCField.CFieldType Shape) "body")
) => GHC.Records.HasField "body" (Ptr.Ptr Shape) (Ptr.Ptr ty) where
getField =
HsBindgen.Runtime.HasCField.fromPtr (Data.Proxy.Proxy @"body")

View File

@ -1,104 +0,0 @@
{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK prune #-}
module GarnetRs.FunPtr where
import qualified Foreign.C as FC
import qualified GHC.IO.Unsafe
import qualified GHC.Ptr as Ptr
import qualified HsBindgen.Runtime.Internal.CAPI
import qualified HsBindgen.Runtime.Internal.HasFFIType
import qualified HsBindgen.Runtime.PtrConst
import Data.Void (Void)
import GarnetRs
import Prelude (IO)
$(HsBindgen.Runtime.Internal.CAPI.addCSource (HsBindgen.Runtime.Internal.CAPI.unlines
[ "#include <garnet_rs.h>"
, "/* com_garnet_GarnetRs_get_hello */"
, "__attribute__ ((const))"
, "void (*hs_bindgen_faf62265b53521d3 (void)) ("
, " char const *arg1"
, ")"
, "{"
, " return &hello;"
, "}"
, "/* com_garnet_GarnetRs_get_hello_struct */"
, "__attribute__ ((const))"
, "void (*hs_bindgen_0f8c37ef19b17a6d (void)) ("
, " struct T arg1"
, ")"
, "{"
, " return &hello_struct;"
, "}"
, "/* com_garnet_GarnetRs_get_hello_shape */"
, "__attribute__ ((const))"
, "void (*hs_bindgen_287ff3ac660f333b (void)) ("
, " struct Shape arg1"
, ")"
, "{"
, " return &hello_shape;"
, "}"
]))
-- __unique:__ @com_garnet_GarnetRs_get_hello@
foreign import ccall unsafe "hs_bindgen_faf62265b53521d3" hs_bindgen_faf62265b53521d3_base ::
IO (Ptr.FunPtr Void)
-- __unique:__ @com_garnet_GarnetRs_get_hello@
hs_bindgen_faf62265b53521d3 :: IO (Ptr.FunPtr ((HsBindgen.Runtime.PtrConst.PtrConst FC.CChar) -> IO ()))
hs_bindgen_faf62265b53521d3 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_faf62265b53521d3_base
{-# NOINLINE hello #-}
{-| __C declaration:__ @hello@
__defined at:__ @garnet_rs.h 32:6@
__exported by:__ @garnet_rs.h@
-}
hello :: Ptr.FunPtr ((HsBindgen.Runtime.PtrConst.PtrConst FC.CChar) -> IO ())
hello =
GHC.IO.Unsafe.unsafePerformIO hs_bindgen_faf62265b53521d3
-- __unique:__ @com_garnet_GarnetRs_get_hello_struct@
foreign import ccall unsafe "hs_bindgen_0f8c37ef19b17a6d" hs_bindgen_0f8c37ef19b17a6d_base ::
IO (Ptr.FunPtr Void)
-- __unique:__ @com_garnet_GarnetRs_get_hello_struct@
hs_bindgen_0f8c37ef19b17a6d :: IO (Ptr.FunPtr (T -> IO ()))
hs_bindgen_0f8c37ef19b17a6d =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_0f8c37ef19b17a6d_base
{-# NOINLINE hello_struct #-}
{-| __C declaration:__ @hello_struct@
__defined at:__ @garnet_rs.h 34:6@
__exported by:__ @garnet_rs.h@
-}
hello_struct :: Ptr.FunPtr (T -> IO ())
hello_struct =
GHC.IO.Unsafe.unsafePerformIO hs_bindgen_0f8c37ef19b17a6d
-- __unique:__ @com_garnet_GarnetRs_get_hello_shape@
foreign import ccall unsafe "hs_bindgen_287ff3ac660f333b" hs_bindgen_287ff3ac660f333b_base ::
IO (Ptr.FunPtr Void)
-- __unique:__ @com_garnet_GarnetRs_get_hello_shape@
hs_bindgen_287ff3ac660f333b :: IO (Ptr.FunPtr (Shape -> IO ()))
hs_bindgen_287ff3ac660f333b =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_287ff3ac660f333b_base
{-# NOINLINE hello_shape #-}
{-| __C declaration:__ @hello_shape@
__defined at:__ @garnet_rs.h 36:6@
__exported by:__ @garnet_rs.h@
-}
hello_shape :: Ptr.FunPtr (Shape -> IO ())
hello_shape =
GHC.IO.Unsafe.unsafePerformIO hs_bindgen_287ff3ac660f333b

View File

@ -1,114 +0,0 @@
{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK prune #-}
module GarnetRs.Safe where
import qualified Foreign as F
import qualified Foreign.C as FC
import qualified GHC.Ptr as Ptr
import qualified HsBindgen.Runtime.Internal.CAPI
import qualified HsBindgen.Runtime.Internal.HasFFIType
import qualified HsBindgen.Runtime.PtrConst
import Data.Void (Void)
import GarnetRs
import Prelude (IO)
$(HsBindgen.Runtime.Internal.CAPI.addCSource (HsBindgen.Runtime.Internal.CAPI.unlines
[ "#include <garnet_rs.h>"
, "void hs_bindgen_433ea2a26af4e593 ("
, " char const *arg1"
, ")"
, "{"
, " hello(arg1);"
, "}"
, "void hs_bindgen_51157946af5519c9 ("
, " struct T *arg1"
, ")"
, "{"
, " hello_struct(*arg1);"
, "}"
, "void hs_bindgen_7de06f1fd827ca60 ("
, " struct Shape *arg1"
, ")"
, "{"
, " hello_shape(*arg1);"
, "}"
]))
-- __unique:__ @com_garnet_GarnetRs_Safe_hello@
foreign import ccall safe "hs_bindgen_433ea2a26af4e593" hs_bindgen_433ea2a26af4e593_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Safe_hello@
hs_bindgen_433ea2a26af4e593 ::
HsBindgen.Runtime.PtrConst.PtrConst FC.CChar
-> IO ()
hs_bindgen_433ea2a26af4e593 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_433ea2a26af4e593_base
{-| __C declaration:__ @hello@
__defined at:__ @garnet_rs.h 32:6@
__exported by:__ @garnet_rs.h@
-}
hello ::
HsBindgen.Runtime.PtrConst.PtrConst FC.CChar
-- ^ __C declaration:__ @c@
-> IO ()
hello = hs_bindgen_433ea2a26af4e593
-- __unique:__ @com_garnet_GarnetRs_Safe_hello_struct@
foreign import ccall safe "hs_bindgen_51157946af5519c9" hs_bindgen_51157946af5519c9_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Safe_hello_struct@
hs_bindgen_51157946af5519c9 ::
Ptr.Ptr T
-> IO ()
hs_bindgen_51157946af5519c9 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_51157946af5519c9_base
{-| __C declaration:__ @hello_struct@
__defined at:__ @garnet_rs.h 34:6@
__exported by:__ @garnet_rs.h@
-}
hello_struct ::
T
-- ^ __C declaration:__ @t@
-> IO ()
hello_struct =
\t0 ->
F.with t0 (\t1 -> hs_bindgen_51157946af5519c9 t1)
-- __unique:__ @com_garnet_GarnetRs_Safe_hello_shape@
foreign import ccall safe "hs_bindgen_7de06f1fd827ca60" hs_bindgen_7de06f1fd827ca60_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Safe_hello_shape@
hs_bindgen_7de06f1fd827ca60 ::
Ptr.Ptr Shape
-> IO ()
hs_bindgen_7de06f1fd827ca60 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_7de06f1fd827ca60_base
{-| __C declaration:__ @hello_shape@
__defined at:__ @garnet_rs.h 36:6@
__exported by:__ @garnet_rs.h@
-}
hello_shape ::
Shape
-- ^ __C declaration:__ @s@
-> IO ()
hello_shape =
\s0 ->
F.with s0 (\s1 -> hs_bindgen_7de06f1fd827ca60 s1)

View File

@ -1,114 +0,0 @@
{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK prune #-}
module GarnetRs.Unsafe where
import qualified Foreign as F
import qualified Foreign.C as FC
import qualified GHC.Ptr as Ptr
import qualified HsBindgen.Runtime.Internal.CAPI
import qualified HsBindgen.Runtime.Internal.HasFFIType
import qualified HsBindgen.Runtime.PtrConst
import Data.Void (Void)
import GarnetRs
import Prelude (IO)
$(HsBindgen.Runtime.Internal.CAPI.addCSource (HsBindgen.Runtime.Internal.CAPI.unlines
[ "#include <garnet_rs.h>"
, "void hs_bindgen_2dfe97662a4d6377 ("
, " char const *arg1"
, ")"
, "{"
, " hello(arg1);"
, "}"
, "void hs_bindgen_29d823ada2bc7302 ("
, " struct T *arg1"
, ")"
, "{"
, " hello_struct(*arg1);"
, "}"
, "void hs_bindgen_b3f40a03f07eaa85 ("
, " struct Shape *arg1"
, ")"
, "{"
, " hello_shape(*arg1);"
, "}"
]))
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello@
foreign import ccall unsafe "hs_bindgen_2dfe97662a4d6377" hs_bindgen_2dfe97662a4d6377_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello@
hs_bindgen_2dfe97662a4d6377 ::
HsBindgen.Runtime.PtrConst.PtrConst FC.CChar
-> IO ()
hs_bindgen_2dfe97662a4d6377 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_2dfe97662a4d6377_base
{-| __C declaration:__ @hello@
__defined at:__ @garnet_rs.h 32:6@
__exported by:__ @garnet_rs.h@
-}
hello ::
HsBindgen.Runtime.PtrConst.PtrConst FC.CChar
-- ^ __C declaration:__ @c@
-> IO ()
hello = hs_bindgen_2dfe97662a4d6377
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello_struct@
foreign import ccall unsafe "hs_bindgen_29d823ada2bc7302" hs_bindgen_29d823ada2bc7302_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello_struct@
hs_bindgen_29d823ada2bc7302 ::
Ptr.Ptr T
-> IO ()
hs_bindgen_29d823ada2bc7302 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_29d823ada2bc7302_base
{-| __C declaration:__ @hello_struct@
__defined at:__ @garnet_rs.h 34:6@
__exported by:__ @garnet_rs.h@
-}
hello_struct ::
T
-- ^ __C declaration:__ @t@
-> IO ()
hello_struct =
\t0 ->
F.with t0 (\t1 -> hs_bindgen_29d823ada2bc7302 t1)
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello_shape@
foreign import ccall unsafe "hs_bindgen_b3f40a03f07eaa85" hs_bindgen_b3f40a03f07eaa85_base ::
Ptr.Ptr Void
-> IO ()
-- __unique:__ @com_garnet_GarnetRs_Unsafe_hello_shape@
hs_bindgen_b3f40a03f07eaa85 ::
Ptr.Ptr Shape
-> IO ()
hs_bindgen_b3f40a03f07eaa85 =
HsBindgen.Runtime.Internal.HasFFIType.fromFFIType hs_bindgen_b3f40a03f07eaa85_base
{-| __C declaration:__ @hello_shape@
__defined at:__ @garnet_rs.h 36:6@
__exported by:__ @garnet_rs.h@
-}
hello_shape ::
Shape
-- ^ __C declaration:__ @s@
-> IO ()
hello_shape =
\s0 ->
F.with s0 (\s1 -> hs_bindgen_b3f40a03f07eaa85 s1)

2
rust/Cargo.lock generated
View File

@ -3,5 +3,5 @@
version = 4 version = 4
[[package]] [[package]]
name = "garnet-rs" name = "garnet"
version = "0.1.0" version = "0.1.0"

View File

@ -1,8 +1,8 @@
[package] [package]
name = "garnet-rs" name = "garnet"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[lib] [[bin]]
path = "lib.rs" path = "main.rs"
crate-type = ["staticlib"] name = "garnet"

View File

@ -1,36 +0,0 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct T {
bool a;
uint8_t b;
} T;
typedef uint8_t Shape_Tag;
#define Circle 0
#define Rectangle 1
typedef struct Circle_Body {
double radius;
} Circle_Body;
typedef struct Rectangle_Body {
double width;
double height;
} Rectangle_Body;
typedef struct Shape {
Shape_Tag tag;
union {
Circle_Body circle;
Rectangle_Body rectangle;
} body;
} Shape;
void hello(const char *c);
void hello_struct(struct T t);
void hello_shape(struct Shape s);

View File

@ -1,34 +0,0 @@
use std::ffi::{CStr, c_char};
fn say_hello(name: &str) {
println!("Hello from Rust, {name}!");
}
#[unsafe(no_mangle)]
extern "C" fn hello(c: *const c_char) -> () {
say_hello(unsafe { CStr::from_ptr(c) }.to_str().unwrap())
}
#[repr(C)]
#[derive(Debug)]
struct T {
a: bool,
b: u8,
}
#[unsafe(no_mangle)]
extern "C" fn hello_struct(t: T) -> () {
say_hello(&format!("{:?}", t))
}
#[repr(C, u8)]
#[allow(dead_code)]
#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[unsafe(no_mangle)]
extern "C" fn hello_shape(s: Shape) -> () {
say_hello(&format!("{:?}", s))
}

3
rust/main.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello from Rust");
}