theatre-dev-0.2: library/TheatreDev/StmStructures/Runner.hs
module TheatreDev.StmStructures.Runner
( Runner,
start,
tell,
kill,
wait,
receiveSingle,
receiveMultiple,
releaseWithException,
releaseNormally,
-- * Inspection
getId,
)
where
import Control.Concurrent.STM.TBQueue
import Control.Concurrent.STM.TMVar
import Data.UUID.V4 qualified as UuidV4
import TheatreDev.ExtrasFor.TBQueue
import TheatreDev.Prelude
data Runner a = Runner
{ queue :: TBQueue a,
receivesVar :: TVar Bool,
resVar :: TMVar (Maybe SomeException),
id :: UUID
}
getId :: Runner a -> UUID
getId = (.id)
start :: IO (Runner a)
start =
do
queue <- newTBQueueIO 1000
receivesVar <- newTVarIO True
resVar <- newEmptyTMVarIO
id <- UuidV4.nextRandom
return Runner {..}
tell :: Runner a -> a -> STM ()
tell Runner {..} message =
do
receives <- readTVar receivesVar
when receives do
writeTBQueue queue message
kill :: Runner a -> STM ()
kill Runner {..} =
writeTVar receivesVar False
wait :: Runner a -> STM (Maybe SomeException)
wait Runner {..} = do
readTMVar resVar
receiveSingle ::
Runner a ->
-- | Action producing a message or nothing, after it's killed.
STM (Maybe a)
receiveSingle Runner {..} =
do
readResult <- tryReadTBQueue queue
case readResult of
Nothing -> do
receives <- readTVar receivesVar
if receives
then retry
else return Nothing
Just message ->
return (Just message)
receiveMultiple ::
Runner a ->
STM (Maybe (NonEmpty a))
receiveMultiple Runner {..} =
do
messages <- correctFlushTBQueue queue
case messages of
[] -> do
receives <- readTVar receivesVar
if receives
then retry
else return Nothing
messagesHead : messagesTail ->
return $ Just $ messagesHead :| messagesTail
releaseWithException :: Runner a -> SomeException -> STM ()
releaseWithException Runner {..} exception =
do
correctFlushTBQueue queue
writeTVar receivesVar False
putTMVar resVar (Just exception)
releaseNormally :: Runner a -> STM ()
releaseNormally Runner {..} = do
writeTVar receivesVar False
putTMVar resVar Nothing <|> pure ()