{-# LANGUAGE GADTs, Rank2Types, LambdaCase #-}
module Control.Object.Instance (
Instance
, new
, newSettle
, invokeOnUsing
, invokeOn
, (.-)
, (..-)
, (?-)
) where
import Control.Concurrent
import Control.Exception (evaluate)
import Control.Object.Object
import Control.Monad.IO.Class
import Control.Monad.Catch
import Control.Monad.Skeleton
type Instance f g = MVar (Object f g)
invokeOnUsing :: (MonadIO m, MonadMask m)
=> (Object f g -> t a -> g (a, Object f g))
-> (forall x. g x -> m x) -> Instance f g -> t a -> m a
invokeOnUsing run m v f = mask $ \restore -> do
obj <- liftIO $ takeMVar v
(a, obj') <- restore (m (run obj f) >>= liftIO . evaluate) `onException` liftIO (putMVar v obj)
liftIO $ putMVar v obj'
return a
invokeOn :: (MonadIO m, MonadMask m)
=> (forall x. g x -> m x) -> Instance f g -> f a -> m a
invokeOn = invokeOnUsing runObject
{-# INLINE invokeOn #-}
(.-) :: (MonadIO m, MonadMask m) => Instance f m -> f a -> m a
(.-) = invokeOn id
{-# INLINE (.-) #-}
infixr 3 .-
(..-) :: (MonadIO m, MonadMask m)
=> Instance t m -> Skeleton t a -> m a
(..-) = invokeOnUsing cascadeObject id
{-# INLINE (..-) #-}
infixr 3 ..-
(?-) :: (MonadIO m, MonadMask m) => Instance f m -> f a -> m (Maybe a)
v ?- f = mask $ \restore -> liftIO (tryTakeMVar v) >>= \case
Just obj -> do
(a, obj') <- restore (runObject obj f >>= liftIO . evaluate) `onException` liftIO (putMVar v obj)
liftIO $ putMVar v obj'
return (Just a)
Nothing -> return Nothing
new :: MonadIO m => Object f g -> m (Instance f g)
new = liftIO . newMVar
{-# INLINE new #-}
newSettle :: MonadIO m => Object f m -> m (Instance f m)
newSettle = new
{-# INLINE newSettle #-}