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