diff --git a/ffitypedemo/cabal.project b/ffitypedemo/cabal.project new file mode 100644 index 000000000..e6fdbadb4 --- /dev/null +++ b/ffitypedemo/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/ffitypedemo/cbits/exporttest.c b/ffitypedemo/cbits/exporttest.c new file mode 100644 index 000000000..c95011f31 --- /dev/null +++ b/ffitypedemo/cbits/exporttest.c @@ -0,0 +1,11 @@ +#include "exporttest.h" + +#include + +void foo(int i) { + printf("foo: %d\n", i); +} + +void bar(struct SomeStruct *s) { + printf("bar: %d %d\n", s->i, s->j); +} diff --git a/ffitypedemo/cbits/exporttest.h b/ffitypedemo/cbits/exporttest.h new file mode 100644 index 000000000..0313c6b2c --- /dev/null +++ b/ffitypedemo/cbits/exporttest.h @@ -0,0 +1,9 @@ +#pragma once + +struct SomeStruct { + int i; + int j; +}; + +void foo(int i); +void bar(struct SomeStruct *s); diff --git a/ffitypedemo/ffitypedemo.cabal b/ffitypedemo/ffitypedemo.cabal new file mode 100644 index 000000000..abf6d5b6f --- /dev/null +++ b/ffitypedemo/ffitypedemo.cabal @@ -0,0 +1,35 @@ +cabal-version: 3.0 +name: ffitypedemo +version: 0.1.0 +license: BSD-3-Clause +author: Edsko de Vries +maintainer: edsko@well-typed.com +build-type: Simple + +common lang + default-language: GHC2021 + build-depends: base >= 4.16 && < 5 + ghc-options: -Wall + + default-extensions: + CApiFFI + DefaultSignatures + DerivingStrategies + TypeFamilies + +executable ffitypedemo + import: lang + hs-source-dirs: src + main-is: Main.hs + + other-modules: + A + B + C + SomeOtherModule + SomeStruct + Runtime + + include-dirs: cbits + c-sources: cbits/exporttest.c + cc-options: -Wall \ No newline at end of file diff --git a/ffitypedemo/src/A.hs b/ffitypedemo/src/A.hs new file mode 100644 index 000000000..8f789eb3d --- /dev/null +++ b/ffitypedemo/src/A.hs @@ -0,0 +1,13 @@ +module A where + +import Foreign +import Runtime + +newtype A = A { unA :: Int } + deriving stock (Show) + deriving newtype (Num, Storable) + +instance HasFFIType A where + type FFIType A = Int + coerceFFI = coerceFFI . unA + diff --git a/ffitypedemo/src/B.hs b/ffitypedemo/src/B.hs new file mode 100644 index 000000000..ce8b92a42 --- /dev/null +++ b/ffitypedemo/src/B.hs @@ -0,0 +1,13 @@ +module B where + +import Foreign +import Runtime +import A + +newtype B = B { unB :: A } + deriving stock (Show) + deriving newtype (Num, Storable) + +instance HasFFIType B where + type FFIType B = Int + coerceFFI = coerceFFI . unB diff --git a/ffitypedemo/src/C.hs b/ffitypedemo/src/C.hs new file mode 100644 index 000000000..f72c5e974 --- /dev/null +++ b/ffitypedemo/src/C.hs @@ -0,0 +1,13 @@ +module C where + +import B +import Foreign +import Runtime + +newtype C = C { unC :: B } + deriving stock (Show) + deriving newtype (Num, Storable) + +instance HasFFIType C where + type FFIType C = Int + coerceFFI = coerceFFI . unC diff --git a/ffitypedemo/src/Main.hs b/ffitypedemo/src/Main.hs new file mode 100644 index 000000000..e90ec9956 --- /dev/null +++ b/ffitypedemo/src/Main.hs @@ -0,0 +1,10 @@ +module Main (main) where + +import SomeOtherModule +import SomeStruct +import Foreign + +main :: IO () +main = do + foo 1234 + with (SomeStruct 12 34) bar diff --git a/ffitypedemo/src/Runtime.hs b/ffitypedemo/src/Runtime.hs new file mode 100644 index 000000000..beed05107 --- /dev/null +++ b/ffitypedemo/src/Runtime.hs @@ -0,0 +1,19 @@ +module Runtime where + +import Data.Kind +import Foreign + +class HasFFIType a where + type FFIType a :: Type + type FFIType a = a + + coerceFFI :: a -> FFIType a + + default coerceFFI :: (a ~ FFIType a) => a -> FFIType a + coerceFFI = id + +instance HasFFIType Int +-- other instances for marshallable types + +instance HasFFIType (Ptr a) + diff --git a/ffitypedemo/src/SomeOtherModule.hs b/ffitypedemo/src/SomeOtherModule.hs new file mode 100644 index 000000000..0b62f4add --- /dev/null +++ b/ffitypedemo/src/SomeOtherModule.hs @@ -0,0 +1,12 @@ +module SomeOtherModule where + +import Runtime +import C + +foreign import capi "exporttest.h foo" + foo_hash1234 :: Int -> IO () + +foo :: C -> IO () +foo c = foo_hash1234 (coerceFFI c) + + diff --git a/ffitypedemo/src/SomeStruct.hsc b/ffitypedemo/src/SomeStruct.hsc new file mode 100644 index 000000000..2d2dd2539 --- /dev/null +++ b/ffitypedemo/src/SomeStruct.hsc @@ -0,0 +1,27 @@ +module SomeStruct where + +import Foreign +import C + +#include "exporttest.h" + +data SomeStruct = SomeStruct { + i :: C + , j :: C + } + +instance Storable SomeStruct where + sizeOf _ = #size struct SomeStruct + alignment _ = #alignment struct SomeStruct + + peek p = do + i <- (#peek struct SomeStruct, i) p + j <- (#peek struct SomeStruct, j) p + return SomeStruct{i, j} + + poke p SomeStruct{i, j} = do + (#poke struct SomeStruct, i) p i + (#poke struct SomeStruct, j) p j + +foreign import capi "exporttest.h bar" + bar :: Ptr SomeStruct -> IO ()