Kalamata Hari on Nostr: Yes. Here's my thoughts so far. (All code is untested.) You need something like ...
Yes.
Here's my thoughts so far. (All code is untested.)
You need something like foreign import ccall "wrapper" mkCallback :: IO () -> IO (FunPtr (IO ())) to turn Haskell actions into C callbacks.
Basic usage (not exception safe):<code>do<br> p <- allocateData<br> onDone <- mkCallback (deallocateData p)<br> c_send p onDone<br></code>
(Also, this leaks onDone, which should be freed using freeHaskellFunPtr when no longer needed.)
As for how to implement allocateData and deallocateData, you could straight up use malloc, copyBytes, and free from Foreign.Marshal.
Things get a bit more interesting if you don't want to make a copy, but use the underlying storage of a ByteString directly. Using Data.ByteString.Internal, you can crack open the ByteString and get the underlying ForeignPtr.<code>case bs of<br> BS fptr _ -> withForeignPtr fptr $ \p -> do<br> onDone <- mkCallback (touchForeignPtr fptr)<br> c_send p onDone<br></code>
Placing touchForeignPtr in the callback should ensure that the foreign pointer stays alive until the callback is invoked.
It may also be possible to play games with useAsCStringLen and threads, preventing the inner action from returning until an MVar is filled (which would be done by the callback).
Here's my thoughts so far. (All code is untested.)
You need something like foreign import ccall "wrapper" mkCallback :: IO () -> IO (FunPtr (IO ())) to turn Haskell actions into C callbacks.
Basic usage (not exception safe):<code>do<br> p <- allocateData<br> onDone <- mkCallback (deallocateData p)<br> c_send p onDone<br></code>
(Also, this leaks onDone, which should be freed using freeHaskellFunPtr when no longer needed.)
As for how to implement allocateData and deallocateData, you could straight up use malloc, copyBytes, and free from Foreign.Marshal.
Things get a bit more interesting if you don't want to make a copy, but use the underlying storage of a ByteString directly. Using Data.ByteString.Internal, you can crack open the ByteString and get the underlying ForeignPtr.<code>case bs of<br> BS fptr _ -> withForeignPtr fptr $ \p -> do<br> onDone <- mkCallback (touchForeignPtr fptr)<br> c_send p onDone<br></code>
Placing touchForeignPtr in the callback should ensure that the foreign pointer stays alive until the callback is invoked.
It may also be possible to play games with useAsCStringLen and threads, preventing the inner action from returning until an MVar is filled (which would be done by the callback).