reactive-thread-0.3.1.0: Reactive/Thread/Internal/DumbSTM.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
module Reactive.Thread.Internal.DumbSTM
( DumbSTMVar
, DumbSTM
, runDumbSTM
, newDumbSTMVar
, readDumbSTMVar
, writeDumbSTMVar
, blockRead
) where
import Control.Applicative
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Parallel
import Control.Monad.Trans.State
import Control.Monad.IO.Class
import Data.List
import Control.Concurrent.STM.TEvent
import Control.Concurrent.STM.TEventVar
import Data.Any
import Reactive.Thread.Internal.VarSource
newtype DumbSTMVar a = DumbSTMVar
{ unDumbSTMVar :: TEventVar a }
deriving (Eq)
newtype VarCache = VarCache [CacheEntry]
data CacheEntry = CacheEntry
{ cacheToken :: !(Any1 DumbSTMVar)
, cacheUpdateEvent :: !TEvent
, cacheValue :: Any0
}
entryIsVar :: forall a. DumbSTMVar a -> CacheEntry -> Bool
entryIsVar var entry = var == any1 (cacheToken entry)
emptyCache :: VarCache
emptyCache = VarCache []
addCache
:: (Monad m)
=> DumbSTMVar a
-> a
-> TEvent
-> StateT VarCache m ()
addCache var x event
= modify $ \ (VarCache entries)
-> VarCache $ cacheEntry : entries
where
cacheEntry = CacheEntry
{ cacheToken = Any1 var
, cacheUpdateEvent = event
, cacheValue = Any0 x
}
readCacheEntry
:: (Monad m)
=> DumbSTMVar a
-> StateT VarCache m (Maybe CacheEntry)
readCacheEntry var = do
VarCache vars <- get
return $ find (entryIsVar var) vars
readCacheValue
:: (Monad m)
=> DumbSTMVar a
-> StateT VarCache m (Maybe a)
readCacheValue
= liftM (fmap (any0 . cacheValue))
. readCacheEntry
cachedEvents
:: (Monad m)
=> StateT VarCache m [TEvent]
cachedEvents = do
VarCache vars <- get
return $ map cacheUpdateEvent vars
newtype DumbSTM a = DumbSTM (StateT VarCache IO a)
deriving
( Monad
, Functor
, Applicative
, MonadIO
)
instance MonadParallel DumbSTM where
bindM2 = error "bindM2: TODO"
instance MonadFork DumbSTM where
forkExec m = do
joiner <- liftIO $ forkExec (runDumbSTM m)
return $ liftIO joiner
runDumbSTM :: DumbSTM a -> IO a
runDumbSTM (DumbSTM m) = evalStateT m emptyCache
newDumbSTMVar :: a -> DumbSTM (DumbSTMVar a)
newDumbSTMVar
= DumbSTM . liftIO . atomically
. liftM DumbSTMVar . newTEventVar
readDumbSTMVar :: DumbSTMVar a -> DumbSTM a
readDumbSTMVar var = DumbSTM $ do
mX <- readCacheValue var
case mX of
Just x -> return x
Nothing -> do
(x, event) <- liftIO . atomically
. readTEventVar $ unDumbSTMVar var
addCache var x event
return x
writeDumbSTMVar :: DumbSTMVar a -> a -> DumbSTM ()
writeDumbSTMVar var x = DumbSTM
. void . liftIO . atomically
$ writeTEventVar (unDumbSTMVar var) x
foldl1Default
:: a -> (a -> a -> a) -> [a] -> a
foldl1Default _ f (x:xs) = foldl f x xs
foldl1Default d _ [] = d
blockRead :: DumbSTM ()
blockRead = DumbSTM $ do
events <- cachedEvents
put emptyCache
liftIO . atomically
. foldl1Default (return ()) orElse
$ map blockTEvent events
instance NewVar DumbSTMVar DumbSTM where
newVar = newDumbSTMVar
instance WriteVar DumbSTMVar DumbSTM where
writeVar = writeDumbSTMVar