module Gnome.Keyring.Operation.Internal where
import Foreign (Ptr)
import qualified Foreign as F
import qualified Gnome.Keyring.Types as T
import qualified Gnome.Keyring.FFI as B
import Control.Exception (throwIO)
data Operation a = Operation
{ async :: (T.Error -> IO ()) -> (a -> IO ()) -> IO T.CancellationKey
, sync :: IO a
}
operation :: B.Callback a b => (a -> Ptr () -> B.DestroyNotifyPtr -> IO T.CancellationKey)
-> IO (T.Result, b) -> Operation b
operation asyncIO syncIO = Operation (runAsync asyncIO) (runSync syncIO)
async' :: Operation a -> (T.Error -> IO ()) -> IO () -> IO T.CancellationKey
async' op onError onSuccess = async op onError (const onSuccess)
runSync :: IO (T.Result, a) -> IO a
runSync io = do
(res, x) <- io
checkResult res
return x
checkResult :: T.Result -> IO ()
checkResult T.RESULT_OK = return ()
checkResult x = throwIO $ T.resultToError x
data Context = Context
{ contextFreeCallback :: IO ()
, contextFreeDestroy :: IO ()
}
destroyNotify :: IO B.DestroyNotifyPtr
destroyNotify = B.wrapDestroyNotify $ \ptr -> do
let stable = F.castPtrToStablePtr ptr
ctx <- F.deRefStablePtr stable
contextFreeCallback ctx
contextFreeDestroy ctx
F.freeStablePtr stable
runAsync :: B.Callback a b => (a -> Ptr () -> B.DestroyNotifyPtr -> IO T.CancellationKey)
-> (T.Error -> IO ()) -> (b -> IO ()) -> IO T.CancellationKey
runAsync io onError onSuccess = do
destroy <- destroyNotify
callback <- B.buildCallback onSuccess onError
let context = Context
(B.freeCallback callback)
(F.freeHaskellFunPtr destroy)
stable <- F.newStablePtr context
io callback (F.castStablePtrToPtr stable) destroy