hasquant-0.8.0.0: QuantLib/Internal/Callback.chs
module QuantLib.Internal.Callback
( Callback, CallbackArgs(..), withCallback, withCallbackPtr, withScalarCallback ) where
import Control.Exception (SomeException, catch, mask, onException)
import Foreign.C.Types (CDouble)
import Foreign.Ptr (Ptr, FunPtr, nullPtr, freeHaskellFunPtr)
import Foreign.ForeignPtr (ForeignPtr, FinalizerPtr, newForeignPtr, withForeignPtr)
import Foreign.StablePtr (StablePtr, newStablePtr, castStablePtrToPtr)
import Foreign.Storable (poke)
import QuantLib.Internal (preErrorCheck, errorCheck)
#include "qlTypesC2HS.h"
#include "qlCallback.h"
newtype Callback = Callback (ForeignPtr ())
type CallbackFun = Ptr () -> IO (Ptr ())
data CallbackArgs = CallbackArgs
{ callbackInput :: Ptr CDouble
, callbackOutput :: Ptr CDouble
, callbackSize :: Int
, callbackInput2 :: Ptr CDouble
, callbackSize2 :: Int
, callbackOutputSize :: Int
, callbackDirection :: Int
, callbackScalar :: Double
, callbackTime1 :: Double
, callbackTime2 :: Double
}
foreign import ccall "wrapper" wrapCallback :: CallbackFun -> IO (FunPtr CallbackFun)
foreign import ccall "&hs_free_fun_ptr" releaseFun :: FunPtr (FunPtr CallbackFun -> IO ())
foreign import ccall "&hs_free_stable_ptr" releaseStable :: FunPtr (StablePtr SomeException -> IO ())
foreign import ccall safe "ql.h qlNewCallback" newCallback
:: FunPtr CallbackFun -> FunPtr (FunPtr CallbackFun -> IO ())
-> FunPtr (StablePtr SomeException -> IO ()) -> Ptr (Ptr ()) -> IO (Ptr ())
foreign import ccall safe "ql.h qlFreeCallback" freeCallback :: Ptr () -> IO ()
foreign import ccall "&qlFreeCallback" callbackFinalizer :: FinalizerPtr ()
withCallbackPtr :: Callback -> (Ptr () -> IO a) -> IO a
withCallbackPtr (Callback p) = withForeignPtr p
peekArgs :: Ptr () -> IO CallbackArgs
peekArgs p = CallbackArgs
<$> {#get QlCallbackArgs->input#} p
<*> {#get QlCallbackArgs->output#} p
<*> (fromIntegral <$> {#get QlCallbackArgs->size#} p)
<*> {#get QlCallbackArgs->input2#} p
<*> (fromIntegral <$> {#get QlCallbackArgs->size2#} p)
<*> (fromIntegral <$> {#get QlCallbackArgs->outputSize#} p)
<*> (fromIntegral <$> {#get QlCallbackArgs->direction#} p)
<*> (realToFrac <$> {#get QlCallbackArgs->s#} p)
<*> (realToFrac <$> {#get QlCallbackArgs->t1#} p)
<*> (realToFrac <$> {#get QlCallbackArgs->t2#} p)
withCallback :: (CallbackArgs -> IO ()) -> (Callback -> IO a) -> IO a
withCallback action use = mask $ \restore -> do
fp <- wrapCallback call
owner <- (preErrorCheck $ \errorPtr -> do
result <- newCallback fp releaseFun releaseStable errorPtr
errorCheck errorPtr
pure result) `onException` freeHaskellFunPtr fp
managed <- newForeignPtr callbackFinalizer owner `onException` freeCallback owner
restore (use (Callback managed))
where
call p = mask $ \restore ->
(restore (peekArgs p >>= action) >> pure nullPtr) `catch` saveException
saveException :: SomeException -> IO (Ptr ())
saveException = fmap castStablePtrToPtr . newStablePtr
withScalarCallback :: (CallbackArgs -> IO Double) -> (Callback -> IO a) -> IO a
withScalarCallback action = withCallback $ \args ->
action args >>= poke (callbackOutput args) . realToFrac