Error when trying to use a ForeignPtr argument to a dynamic wrapper

137 Views Asked by At

I'm trying to wrap a C library using c2hs. I've got an opaque C struct that I've mapped in Haskell as follows:

{#pointer *foo as Foo foreign newtype #}

I've used a foreign pointer so I can automatically clean up with a finalizer. All of that seems to work fine. However, I now want to wrap a function pointer that looks like the following:

typedef void (*hook_func)(foo *f, int a);

My Haskell code then looks like this:

type HookFunc = Foo -> Int -> IO ()
foreign import ccall "wrapper"
    mkHookFunc :: HookFunc -> IO (FunPtr HookFunc)

However, when I compile I get the following error:

Unacceptable argument type in foreign declaration:
    ForeignPtr Foo

Any ideas on the best solution to this error? My initial thinking is that I need to use unsafeForeignPtrToPtr to convert to just a foo pointer, but I'm not sure how to do this/where to put it in the "wrapper".

Any clues?

1

There are 1 best solutions below

0
On

I think I sorted it out.

I ended up finding some code in gtk2hs that did something similar to what I wanted (https://github.com/gtk2hs/gtk2hs/blob/master/gio/System/GIO/Async/AsyncResult.chs)

I defined my callback as normal:

type HookFunc = Foo -> Int -> IO ()

Then I also defined another type that used types from Foreign.C, i.e.

type CHookFunc = Foo -> CInt -> IO ()

The wrapper then looked like:

foreign import "wrapper"
    mkHookFunc :: CHookFunc -> IO {# type hook_func_t #} -- hook_func_t is the typedef in the C header file

Finally, I added a marshalling function as follows:

marshalHookFunc :: HookFunc -> IO {# type hook_func_t #}
marshalHookFunc hookFunc =
    mkHookFunc $ \fooPtr i -> do
        foo <- mkFoo fooPtr -- mkFoo constructs a ForeignPtr Foo out of a Ptr Foo
        hookFunc foo i