-- | -- Module : Simulation.Aivika.Gate -- Copyright : Copyright (c) 2009-2017, David Sorokin -- License : BSD3 -- Maintainer : David Sorokin -- Stability : experimental -- Tested with: GHC 8.0.1 -- -- The module defines a gate which can be either opened or closed. -- module Simulation.Aivika.Gate (Gate, newGate, newGateOpened, newGateClosed, openGate, closeGate, invertGate, gateOpened, gateClosed, awaitGateOpened, awaitGateClosed, gateChanged_) where import Control.Monad import Simulation.Aivika.Simulation import Simulation.Aivika.Event import Simulation.Aivika.Process import Simulation.Aivika.Signal import Simulation.Aivika.Ref -- | Represents a gate, which can be either opened or closed. data Gate = Gate { gateRef :: Ref Bool } -- | Create a new gate, specifying whether the gate is initially open. newGate :: Bool -> Simulation Gate newGate opened = do r <- newRef opened return Gate { gateRef = r } -- | Create a new initially open gate. newGateOpened :: Simulation Gate newGateOpened = newGate True -- | Create a new initially close gate. newGateClosed :: Simulation Gate newGateClosed = newGate False -- | Open the gate if it was closed. openGate :: Gate -> Event () openGate gate = writeRef (gateRef gate) True -- | Close the gate if it was open. closeGate :: Gate -> Event () closeGate gate = writeRef (gateRef gate) False -- | Invert the gate. invertGate :: Gate -> Event () invertGate gate = modifyRef (gateRef gate) not -- | Test whether the gate is open. gateOpened :: Gate -> Event Bool gateOpened gate = readRef (gateRef gate) -- | Test whether the gate is closed. gateClosed :: Gate -> Event Bool gateClosed gate = fmap not $ readRef (gateRef gate) -- | Await the gate to be opened if required. If the gate is already open -- then the computation returns immediately. awaitGateOpened :: Gate -> Process () awaitGateOpened gate = do f <- liftEvent $ readRef (gateRef gate) unless f $ do processAwait $ refChanged_ (gateRef gate) awaitGateOpened gate -- | Await the gate to be closed if required. If the gate is already closed -- then the computation returns immediately. awaitGateClosed :: Gate -> Process () awaitGateClosed gate = do f <- liftEvent $ readRef (gateRef gate) when f $ do processAwait $ refChanged_ (gateRef gate) awaitGateClosed gate -- | Signal triggered when the state of the gate changes. gateChanged_ :: Gate -> Signal () gateChanged_ gate = refChanged_ (gateRef gate)