Suppose you have a C API provides that provides a C struct
typedef struct A {
int i;
float f;
} A;
and a function that populates it:
void getA(A* a);
For example, this could be a getter for some information from the innards of the C API.
In Haskell the C struct would be mirrored by
data A = A {
i :: Int,
f :: Float
}
The Storable
instance is
instance Storable A where
sizeOf _ = {#sizeof A #}
alignment _ = {#alignof A #}
peek p = ...
poke p x = ...
Peek and poke are business as usual with the {#get...#}
and {#set #}
pragmas processed by c2hs.
The Haskell function getA :: IO A
should be something like
{#fun unsafe getA as getA {alloca- `A' peek*} -> `()'#}
except this doesn't work because c2hs creates this binding:
foreign import ccall unsafe "include/A.h getA"
_getA'_ :: Ptr () -> IO ()
It has Ptr ()
as first argument. This can be sorted out by
{#fun unsafe getA as getA {allocaA- `A' peekA*} -> `()'#}
peekA :: Ptr () -> IO A
peekA = peek . castPtr
allocaA :: (Ptr () -> IO a) -> IO a
allocaA f = alloca $ \(p :: Ptr A) -> f (castPtr p)
The allocaA
is important because it ensures that memory for an A
is allocated instead of memory for just a ()
if alloca
were used.
Although this works it is somewhat tedious and you have guaranteed segfaults if you ever forget to write allocaXYZ
instead of just alloca
. (I just saw a good amount of time being spent on tracking down one such error.)
I expected to find a {#fun...#}
incantation that produces
foreign import ccall unsafe "include/A.h getA"
_getA'_ :: Ptr A -> IO ()
from which all else would follow naturally (note the Ptr A
instead of Ptr ()
). But as far as I can tell there's only the {allocXYZ- 'XYZ' peekXYZ*}
route.
So the question is: Can this be done in a better way using c2hs
?