content: 
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE TypeFamilies #-}
  
  -- | This module provides the equivalent of a 'IORef' in the Sunroof world.
  module Language.Sunroof.JS.Ref
          ( JSRef
          , newJSRef
          , readJSRef
          , writeJSRef
          , modifyJSRef
          ) where
  
  import Data.Boolean ( BooleanOf, IfB(..), EqB(..) )
  
  import Language.Sunroof.Classes ( Sunroof(..) )
  import Language.Sunroof.Types ( T(..), JS(..), evaluate, new, (#), liftJS )
  import Language.Sunroof.Selector ( (!) )
  import Language.Sunroof.JS.Object ( JSObject )
  import Language.Sunroof.JS.Bool ( JSBool, jsIfB )
  
  -- -------------------------------------------------------------
  -- JSRef Type
  -- -------------------------------------------------------------
  
  -- | This is the 'IORef' of Sunroof.
  newtype JSRef a = JSRef JSObject
  
  instance (Sunroof a) => Show (JSRef a) where
    show (JSRef o) = show o
  
  instance (Sunroof a) => Sunroof (JSRef a) where
    box = JSRef . box
    unbox (JSRef o) = unbox o
  
  type instance BooleanOf (JSRef a) = JSBool
  
  instance (Sunroof a) => IfB (JSRef a) where
    ifB = jsIfB
  
  -- | Reference equality, not value equality.
  instance (Sunroof a) => EqB (JSRef a) where
    (JSRef a) ==* (JSRef b) = a ==* b
  
  -- -------------------------------------------------------------
  -- JSRef Combinators
  -- -------------------------------------------------------------
  
  -- | Create a new 'JSRef' with the given intial value.
  newJSRef :: (Sunroof a) => a -> JS t (JSRef a)
  newJSRef a = do
    obj <- new "Object" ()
    obj # "val" := a
    return $ JSRef obj
  
  -- | Non-blocking read of a 'JSRef'.
  readJSRef :: (Sunroof a) => JSRef a -> JS t a
  readJSRef (JSRef obj) = evaluate $ obj ! "val"
  
  -- | Non-blocking write of a 'JSRef'.
  writeJSRef :: (Sunroof a) => a -> JSRef a ->  JS t ()
  writeJSRef a (JSRef obj) = obj # "val" := a
  
  -- | Non-blocking modification of a 'JSRef'.
  modifyJSRef :: (Sunroof a) => (a -> JS 'A a) -> JSRef a -> JS t ()
  modifyJSRef f ref = do
    val <- readJSRef ref
    liftJS (f val) >>= \ v -> ref # writeJSRef v
  