packages feed

ramus-0.1.1: library/Ramus/Internal.hs

module Ramus.Internal where

import Data.IORef
import System.IO.Unsafe
import Control.Monad
import Data.Monoid

data Signal a = Signal
  { get :: a
  , set :: a -> IO ()
  , subscribe :: (a -> IO ()) -> IO ()
  }

unsafeRef :: a -> IORef a
unsafeRef = unsafePerformIO . newIORef

unsafeRead :: IORef a -> a
unsafeRead = unsafePerformIO . readIORef

make :: a -> Signal a
make initial = unsafePerformIO $ do
  subs <- newIORef [] :: IO (IORef [a -> IO()])
  val  <- newIORef initial
  let _get = unsafeRead val
  let _set newval = do
        writeIORef val newval
        forM_ (unsafeRead subs) $ \sub ->
          sub newval
  let _subscribe sub = do
        currentSubs <- readIORef subs
        _val <- readIORef val
        writeIORef subs $ currentSubs <> [sub]
        sub _val
  return Signal
    { get = _get
    , set = _set
    , subscribe = _subscribe
    }