module Database.CQL.IO.Sync
    ( Sync
    , create
    , get
    , put
    , kill
    , close
    ) where
import Control.Applicative
import Control.Concurrent.STM
import Control.Exception (SomeException, Exception, toException)
import Prelude
data State a
    = Empty
    | Value  !a
    | Killed !SomeException
    | Closed !SomeException
newtype Sync a = Sync (TVar (State a))
create :: IO (Sync a)
create = Sync <$> newTVarIO Empty
get :: Sync a -> IO a
get (Sync s) = atomically $ do
    v <- readTVar s
    case v of
        Empty    -> retry
        Value  a -> writeTVar s Empty >> return a
        Closed x -> throwSTM x
        Killed x -> throwSTM x
put :: a -> Sync a -> IO Bool
put a (Sync s) = atomically $ do
    v <- readTVar s
    case v of
        Empty    -> writeTVar s (Value a) >> return True
        Closed _ -> return True
        _        -> writeTVar s Empty     >> return False
kill :: Exception e => e -> Sync a -> IO ()
kill x (Sync s) = atomically $ do
    v <- readTVar s
    case v of
        Closed _ -> return ()
        _        -> writeTVar s (Killed $ toException x)
close :: Exception e => e -> Sync a -> IO ()
close x (Sync s) = atomically $ writeTVar s (Closed $ toException x)