module Control.Concurrent.Classy.STM.TChan
(
TChan
, newTChan
, newBroadcastTChan
, dupTChan
, cloneTChan
, readTChan
, tryReadTChan
, peekTChan
, tryPeekTChan
, writeTChan
, unGetTChan
, isEmptyTChan
) where
import Control.Monad.STM.Class
data TChan stm a = TChan (TVar stm (TVarList stm a))
(TVar stm (TVarList stm a))
type TVarList stm a = TVar stm (TList stm a)
data TList stm a = TNil | TCons a (TVarList stm a)
newTChan :: MonadSTM stm => stm (TChan stm a)
newTChan = do
hole <- newTVar TNil
readH <- newTVar hole
writeH <- newTVar hole
pure (TChan readH writeH)
newBroadcastTChan :: MonadSTM stm => stm (TChan stm a)
newBroadcastTChan = do
hole <- newTVar TNil
readT <- newTVar (error "reading from a TChan created by newBroadcastTChan; use dupTChan first")
writeT <- newTVar hole
pure (TChan readT writeT)
writeTChan :: MonadSTM stm => TChan stm a -> a -> stm ()
writeTChan (TChan _ writeT) a = do
listend <- readTVar writeT
listend' <- newTVar TNil
writeTVar listend (TCons a listend')
writeTVar writeT listend'
readTChan :: MonadSTM stm => TChan stm a -> stm a
readTChan tchan = tryReadTChan tchan >>= maybe retry pure
tryReadTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)
tryReadTChan (TChan readT _) = do
listhead <- readTVar readT
hd <- readTVar listhead
case hd of
TNil -> pure Nothing
TCons a tl -> do
writeTVar readT tl
pure (Just a)
peekTChan :: MonadSTM stm => TChan stm a -> stm a
peekTChan tchan = tryPeekTChan tchan >>= maybe retry pure
tryPeekTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)
tryPeekTChan (TChan readT _) = do
listhead <- readTVar readT
hd <- readTVar listhead
pure $ case hd of
TNil -> Nothing
TCons a _ -> Just a
dupTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)
dupTChan (TChan _ writeT) = do
hole <- readTVar writeT
readT' <- newTVar hole
pure (TChan readT' writeT)
unGetTChan :: MonadSTM stm => TChan stm a -> a -> stm ()
unGetTChan (TChan readT _) a = do
listhead <- readTVar readT
head' <- newTVar (TCons a listhead)
writeTVar readT head'
isEmptyTChan :: MonadSTM stm => TChan stm a -> stm Bool
isEmptyTChan (TChan readT _) = do
listhead <- readTVar readT
hd <- readTVar listhead
pure $ case hd of
TNil -> True
TCons _ _ -> False
cloneTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)
cloneTChan (TChan readT writeT) = do
readpos <- readTVar readT
readT' <- newTVar readpos
pure (TChan readT' writeT)