import Control.Concurrent
import Control.Concurrent.STM

data ChanT a = Chan (TVar [a]) (TVar [a])

newChanT :: STM (ChanT a)
newChanT = do
  l1 <- newTVar []
  l2 <- newTVar []
  return (Chan l1 l2)

writeChanT :: ChanT a -> a -> STM ()
writeChanT (Chan o i) v = do
  msgs <- readTVar i
  writeTVar i (v:msgs)

readChanT  :: ChanT a -> STM a
readChanT (Chan o i) = do
  outs <- readTVar o
  if null outs
    then do
      ins <- readTVar i
      if null ins
        then retry
        else do
          writeTVar i []
          let (v:newOuts) = reverse ins
          writeTVar o newOuts
          return v
    else do
      writeTVar o (tail outs)
      return (head outs)

isEmptyChanT :: ChanT a -> STM Bool
isEmptyChanT (Chan o i) = do
  outs <- readTVar o
  ins <- readTVar i
  return (null (outs++ins))

unGetChanT :: ChanT a -> a -> STM ()
unGetChanT (Chan o i) v = do
  msgs <- readTVar o
  writeTVar o (v:msgs)
