packages feed

croaring-ffi-1.0: src/Data/Bitmap/Roaring/FFI/Callback.hs

-- | Running Haskell functions as CRoaring iteration callbacks without leaking the function pointer or unwinding an exception through C.
module Data.Bitmap.Roaring.FFI.Callback (with) where

import Control.Exception (SomeException, bracket, catch, evaluate, throwIO)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Foreign.Ptr (FunPtr, Ptr, freeHaskellFunPtr)

-- | An exception from the visiting function stops the iteration as if it had returned 'False', and is rethrown once the iteration has returned.
with
  :: ((element -> Ptr () -> IO Bool) -> IO (FunPtr (element -> Ptr () -> IO Bool)))
  -> (element -> IO Bool)
  -> (FunPtr (element -> Ptr () -> IO Bool) -> IO Bool)
  -> IO Bool
with wrap visit run = do
  failure <- newIORef Nothing
  completed <- bracket (wrap $ callback failure) freeHaskellFunPtr run
  readIORef failure >>= maybe (pure completed) throwIO
  where
    callback failure element _ = (visit element >>= evaluate) `catch` stop failure
    stop :: IORef (Maybe SomeException) -> SomeException -> IO Bool
    stop failure exception = False <$ writeIORef failure (Just exception)