I’m trying to map a C library to Haskell using capi
instead of ccall
if possible. I’m having problems with these types in C though:
typedef struct {
char _[24];
}* AsapoConsumerHandle;
If I map this as type AsapoConsumerHandle = Ptr ()
(because you’re not supposed to inspect the pointer anyways), as such:
type AsapoConsumerHandle = Ptr ()
foreign import capi "asapo/consumer_c.h asapo_create_consumer" asapo_create_consumer :: IO AsapoConsumerHandle
Then capi
complains:
note: expected ‘struct <anonymous> **’ but argument is of type ‘void **’
67 | AsapoErrorHandle* error);
But I’m not sure how to map this anonymous struct capi
compatible.
1 Like
You should be able to use a CTYPE
pragma to assign the name to the handle, something like
newtype {-# CTYPE "asapo/consumer_c.h" "AsapoConsumerHandle" #-}
AsapoConsumerHandle = AsapoConsumerHandle (Ptr CChar)
3 Likes
Interesting! That works.
But I now realize that…the other thing also works. It outputs an error, but still compiles. Weird.
I am confused now. Let’s assume I have this:
newtype
{-# CTYPE "asapo/common/common_c.h" "AsapoErrorHandle" #-} AsapoErrorHandle =
AsapoErrorHandle (Ptr CChar)
foreign import capi "asapo/consumer_c.h asapo_new_handle" asapo_new_handle :: IO AsapoErrorHandle
So I can create a handle using asapo_new_handle
, fine. Then there are functions that fill these handles:
foreign import capi "asapo/consumer_c.h asapo_consumer_generate_new_group_id" asapo_consumer_generate_new_group_id :: AsapoConsumerHandle -> Ptr AsapoErrorHandle -> IO ()
I thought I’d create a handle and then use with
to get a pointer to use it in the second function:
consumer <- ...
errorHandle <- asapo_new_handle
with errorHandle $ \errorHandlePtr -> asapo_consumer_generate_new_group_id consumer errorHandlePtr
This doesn’t work, “of course”, because with
assumes something Storable
, but my newtype
isn’t. Should I use GeneralizedNewtypeDeriving
to derive Storable? Or extract/cast the pointer?
You can write a custom withErrorHandle
function (since with
is just alloca
plus poke
) or you can derive a newtype Storable
(which will pollute documentation, but is way more convenient). Neither solution feels good, but either works well enough.