module Haskus.Utils.STM.SnapVar
( SnapVar
, SnapContext
, newSnapContextIO
, newSnapContext
, newSnapVarIO
, newSnapVar
, writeSnapVar
, writeSnapVarIO
, readSnapVar
, readSnapVarIO
, modifySnapVar
, modifySnapVarIO
, withSnapshot
, readSnapshot
, readSnapshotIO
)
where
import Haskus.Utils.STM
import Haskus.Utils.Monad
data SnapVar a = SnapVar
{ snapContext :: !SnapContext
, snapValue :: !(TVar a)
, snapNextValue :: !(TVar (Maybe a))
}
data SnapContext = SnapContext
{ snapContextState :: !(TVar SnapState)
, snapContextUpdaters :: !(TVar [STM ()])
}
data SnapState
= NoSnapshot
| Snapshot
| SnapshotExit
newSnapContextIO :: MonadIO m => m SnapContext
newSnapContextIO = SnapContext <$> newTVarIO NoSnapshot <*> newTVarIO []
newSnapContext :: STM SnapContext
newSnapContext = SnapContext <$> newTVar NoSnapshot <*> newTVar []
newSnapVarIO :: MonadIO m => SnapContext -> a -> m (SnapVar a)
newSnapVarIO ctx v = SnapVar <$> return ctx <*> newTVarIO v <*> newTVarIO Nothing
newSnapVar :: SnapContext -> a -> STM (SnapVar a)
newSnapVar ctx v = SnapVar <$> return ctx <*> newTVar v <*> newTVar Nothing
writeSnapVar :: SnapVar a -> a -> STM ()
writeSnapVar v a = do
state <- readTVar (snapContextState (snapContext v))
case state of
NoSnapshot -> writeTVar (snapValue v) a
SnapshotExit -> do
writeTVar (snapValue v) a
writeTVar (snapNextValue v) Nothing
Snapshot -> do
mv <- swapTVar (snapNextValue v) (Just a)
case mv of
Just _ -> return ()
Nothing -> modifyTVar (snapContextUpdaters (snapContext v)) (updateSnapVar v:)
updateSnapVar :: SnapVar a -> STM ()
updateSnapVar v = do
nv <- readTVar (snapNextValue v)
writeTVar (snapNextValue v) Nothing
case nv of
Just val -> writeTVar (snapValue v) val
Nothing -> return ()
writeSnapVarIO :: MonadIO m => SnapVar a -> a -> m ()
writeSnapVarIO v a = atomically (writeSnapVar v a)
readSnapVar :: SnapVar a -> STM a
readSnapVar v = do
state <- readTVar (snapContextState (snapContext v))
case state of
NoSnapshot -> readTVar (snapValue v)
_ -> do
mv <- readTVar (snapNextValue v)
case mv of
Just a -> return a
Nothing -> readTVar (snapValue v)
readSnapVarIO :: MonadIO m => SnapVar a -> m a
readSnapVarIO v = atomically (readSnapVar v)
modifySnapVar :: SnapVar a -> (a -> a) -> STM a
modifySnapVar v f = do
old <- readSnapVar v
writeSnapVar v (f old)
return old
modifySnapVarIO :: MonadIO m => SnapVar a -> (a -> a) -> m a
modifySnapVarIO v f = atomically (modifySnapVar v f)
readSnapshotIO :: MonadIO m => SnapVar a -> m a
readSnapshotIO v = readTVarIO (snapValue v)
readSnapshot :: SnapVar a -> STM a
readSnapshot v = readTVar (snapValue v)
withSnapshot :: MonadIO m => SnapContext -> m r -> m r
withSnapshot ctx action = do
old <- swapTVarIO (snapContextState ctx) Snapshot
case old of
NoSnapshot -> return ()
_ -> error "withSnapshot: invalid snapshot state"
r <- action
writeTVarIO (snapContextState ctx) SnapshotExit
updaters <- readTVarIO (snapContextUpdaters ctx)
forM_ updaters atomically
writeTVarIO (snapContextState ctx) NoSnapshot
return r