{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
module Internal.TCloseQ
( Q
, ErrClosed(..)
, new
, read
, write
, close
) where
import Prelude hiding (read)
import Control.Concurrent.STM
import Control.Exception (Exception)
import Control.Monad (unless, when)
import Data.Maybe (isNothing)
data Q a = Q
{ q :: TQueue (Maybe a)
, isClosed :: TVar Bool
}
data ErrClosed = ErrClosed
deriving(Show)
instance Exception ErrClosed
new :: STM (Q a)
new = do
q <- newTQueue
isClosed <- newTVar False
pure Q{..}
read :: Q a -> STM (Maybe a)
read Q{q} = do
ret <- readTQueue q
when (isNothing ret) $
writeTQueue q ret
pure ret
write :: Q a -> a -> STM ()
write Q{q, isClosed} v = do
c <- readTVar isClosed
when c $ throwSTM ErrClosed
writeTQueue q (Just v)
close :: Q a -> STM ()
close Q{q, isClosed} = do
c <- readTVar isClosed
unless c $ do
writeTVar isClosed True
writeTQueue q Nothing