{-# 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 a -> TQueue (Maybe a)
q :: TQueue (Maybe a)
, Q a -> TVar Bool
isClosed :: TVar Bool
}
data ErrClosed = ErrClosed
deriving(Int -> ErrClosed -> ShowS
[ErrClosed] -> ShowS
ErrClosed -> String
(Int -> ErrClosed -> ShowS)
-> (ErrClosed -> String)
-> ([ErrClosed] -> ShowS)
-> Show ErrClosed
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ErrClosed] -> ShowS
$cshowList :: [ErrClosed] -> ShowS
show :: ErrClosed -> String
$cshow :: ErrClosed -> String
showsPrec :: Int -> ErrClosed -> ShowS
$cshowsPrec :: Int -> ErrClosed -> ShowS
Show)
instance Exception ErrClosed
new :: STM (Q a)
new :: STM (Q a)
new = do
TQueue (Maybe a)
q <- STM (TQueue (Maybe a))
forall a. STM (TQueue a)
newTQueue
TVar Bool
isClosed <- Bool -> STM (TVar Bool)
forall a. a -> STM (TVar a)
newTVar Bool
False
Q a -> STM (Q a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Q :: forall a. TQueue (Maybe a) -> TVar Bool -> Q a
Q{TVar Bool
TQueue (Maybe a)
isClosed :: TVar Bool
q :: TQueue (Maybe a)
isClosed :: TVar Bool
q :: TQueue (Maybe a)
..}
read :: Q a -> STM (Maybe a)
read :: Q a -> STM (Maybe a)
read Q{TQueue (Maybe a)
q :: TQueue (Maybe a)
q :: forall a. Q a -> TQueue (Maybe a)
q} = do
Maybe a
ret <- TQueue (Maybe a) -> STM (Maybe a)
forall a. TQueue a -> STM a
readTQueue TQueue (Maybe a)
q
Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
ret) (STM () -> STM ()) -> STM () -> STM ()
forall a b. (a -> b) -> a -> b
$
TQueue (Maybe a) -> Maybe a -> STM ()
forall a. TQueue a -> a -> STM ()
writeTQueue TQueue (Maybe a)
q Maybe a
ret
Maybe a -> STM (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
ret
write :: Q a -> a -> STM ()
write :: Q a -> a -> STM ()
write Q{TQueue (Maybe a)
q :: TQueue (Maybe a)
q :: forall a. Q a -> TQueue (Maybe a)
q, TVar Bool
isClosed :: TVar Bool
isClosed :: forall a. Q a -> TVar Bool
isClosed} a
v = do
Bool
c <- TVar Bool -> STM Bool
forall a. TVar a -> STM a
readTVar TVar Bool
isClosed
Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
c (STM () -> STM ()) -> STM () -> STM ()
forall a b. (a -> b) -> a -> b
$ ErrClosed -> STM ()
forall e a. Exception e => e -> STM a
throwSTM ErrClosed
ErrClosed
TQueue (Maybe a) -> Maybe a -> STM ()
forall a. TQueue a -> a -> STM ()
writeTQueue TQueue (Maybe a)
q (a -> Maybe a
forall a. a -> Maybe a
Just a
v)
close :: Q a -> STM ()
close :: Q a -> STM ()
close Q{TQueue (Maybe a)
q :: TQueue (Maybe a)
q :: forall a. Q a -> TQueue (Maybe a)
q, TVar Bool
isClosed :: TVar Bool
isClosed :: forall a. Q a -> TVar Bool
isClosed} = do
Bool
c <- TVar Bool -> STM Bool
forall a. TVar a -> STM a
readTVar TVar Bool
isClosed
Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
c (STM () -> STM ()) -> STM () -> STM ()
forall a b. (a -> b) -> a -> b
$ do
TVar Bool -> Bool -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar Bool
isClosed Bool
True
TQueue (Maybe a) -> Maybe a -> STM ()
forall a. TQueue a -> a -> STM ()
writeTQueue TQueue (Maybe a)
q Maybe a
forall a. Maybe a
Nothing