{-# 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