module Simulation.Aivika.Dynamics.Ref
(Ref,
refQueue,
refChanged,
refChanged_,
newRef,
readRef,
writeRef,
modifyRef) where
import Data.IORef
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Dynamics.Internal.Simulation
import Simulation.Aivika.Dynamics.Internal.Dynamics
import Simulation.Aivika.Dynamics.EventQueue
import Simulation.Aivika.Dynamics.Internal.Signal
data Ref a =
Ref { refQueue :: EventQueue,
refRun :: Dynamics (),
refValue :: IORef a,
refChangedSource :: SignalSource a,
refUpdatedSource :: SignalSource a }
newRef :: EventQueue -> a -> Simulation (Ref a)
newRef q a =
do x <- liftIO $ newIORef a
s <- newSignalSourceUnsafe
u <- newSignalSourceWithUpdate (runQueue q)
return Ref { refQueue = q,
refRun = runQueueSync q,
refValue = x,
refChangedSource = s,
refUpdatedSource = u }
readRef :: Ref a -> Dynamics a
readRef r = Dynamics $ \p ->
do invokeDynamics p $ refRun r
readIORef (refValue r)
writeRef :: Ref a -> a -> Dynamics ()
writeRef r a = Dynamics $ \p ->
do a `seq` writeIORef (refValue r) a
invokeDynamics p $ triggerSignal (refChangedSource r) a
modifyRef :: Ref a -> (a -> a) -> Dynamics ()
modifyRef r f = Dynamics $ \p ->
do invokeDynamics p $ refRun r
a <- readIORef (refValue r)
let b = f a
b `seq` writeIORef (refValue r) b
invokeDynamics p $ triggerSignal (refChangedSource r) b
refChanged :: Ref a -> Signal a
refChanged v = merge2Signals m1 m2
where m1 = publishSignal (refUpdatedSource v)
m2 = publishSignal (refChangedSource v)
refChanged_ :: Ref a -> Signal ()
refChanged_ r = mapSignal (const ()) $ refChanged r
invokeDynamics :: Point -> Dynamics a -> IO a
invokeDynamics p (Dynamics m) = m p