ghcjs-vdom-0.2.0.0: src/GHCJS/VDOM/Internal/Thunk.hs
{-# LANGUAGE TemplateHaskell, QuasiQuotes, LambdaCase, GHCForeignImportPrim #-}
{-|
Code that deals with forcing thunks in virtual-dom trees. When
computing a diff, the virtual-dom code returns a list of thunks
found in the tree. The caller then forces the thunks and recurses
into them to advance the diff computation, until all thunks have
been evaluated.
-}
module GHCJS.VDOM.Internal.Thunk where
import GHCJS.Foreign.QQ
import GHCJS.Prim
import Control.Exception
import Control.Monad
import GHC.Exts (Any)
import Unsafe.Coerce
import GHCJS.VDOM.Internal (j,J)
import qualified GHCJS.VDOM.Internal as I
import GHCJS.VDOM.Internal.Types
diff' :: J -> J -> IO J
diff' a b = do
thunks <- [jsu| [] |]
p <- [jsu| h$vdom.diff(`a, `b, `thunks) |]
forceThunks thunks
forcePatch p
return p
forceThunks :: J -> IO ()
forceThunks thunks
| [j| `thunks.length > 0 |] = fromJSArray thunks >>= mapM_ forceNode
| otherwise = return ()
where
forceNode n = do
forceThunkNode [j| `n.a |]
forceThunkNode [j| `n.b |]
patch <- diff' [j| `n.a.vnode |] [j| `n.b.vnode |]
[jsu_| h$vdom.setThunkPatch(`n, `patch); |]
forceThunkNode :: J -> IO ()
forceThunkNode x =
[jsu| `x && `x.hst && !`x.vnode |] >>= \case
True -> do
(VNode u) <- fmap unsafeCoerce . js_toHeapObject =<< I.getThunk x
[jsu| `x.hst = null;
`x.vnode = `u;
|]
_ -> return ()
forcePatch :: J -> IO ()
forcePatch p = do
thunks <- [jsu| h$vdom.forcePatch(`p) |]
forceTree [thunks]
forceTree :: [J] -> IO ()
forceTree [] = return ()
forceTree (x:xs) = do
x' <- fromJSArray x
ys <- forM x' $ \t -> do
forceThunkNode t
newThunks <- [jsu| [] |]
[jsu_| h$vdom.forceTree(`t.vnode, `newThunks) |]
return newThunks
forceTree (filter (\a -> [jsu'| `a.length !== 0 |]) ys ++ xs)
foreign import javascript unsafe
"$r = $1;" js_toHeapObject :: JSVal -> IO Any