{-# LANGUAGE OverloadedStrings #-}
module Miso.Subscription.RAF
( rAFSub
, rAFSubElapsed
) where
import Control.Monad (void)
import Data.IORef
import Miso.DSL
import Miso.Effect (Sub)
import Miso.Subscription.Util (createSub)
rAFSub
:: (Double -> action)
-> Sub action
rAFSub :: forall action. (Double -> action) -> Sub action
rAFSub Double -> action
toAction Sink action
sink = IO JSVal -> (JSVal -> IO ()) -> Sub action
forall a b action. IO a -> (a -> IO b) -> Sub action
createSub IO JSVal
acquire JSVal -> IO ()
release Sink action
sink
where
acquire :: IO JSVal
acquire = do
IORef JSVal
ref <- JSVal -> IO (IORef JSVal)
forall a. a -> IO (IORef a)
newIORef ([Char] -> JSVal
forall a. HasCallStack => [Char] -> a
error [Char]
"rAFSub: uninitialized, impossible")
JSVal
callback <-
(JSVal -> IO ()) -> IO JSVal
syncCallback1 ((JSVal -> IO ()) -> IO JSVal) -> (JSVal -> IO ()) -> IO JSVal
forall a b. (a -> b) -> a -> b
$ \JSVal
jsval -> do
Sink action
sink Sink action -> (Double -> action) -> Double -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> action
toAction (Double -> IO ()) -> IO Double -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< JSVal -> IO Double
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked JSVal
jsval
IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (JSVal -> IO Int
requestAnimationFrame (JSVal -> IO Int) -> IO JSVal -> IO Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef JSVal -> IO JSVal
forall a. IORef a -> IO a
readIORef IORef JSVal
ref)
IORef JSVal -> JSVal -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef JSVal
ref JSVal
callback
IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (JSVal -> IO Int
requestAnimationFrame JSVal
callback)
JSVal -> IO JSVal
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JSVal
callback
release :: JSVal -> IO ()
release JSVal
callback = Function -> IO ()
freeFunction (JSVal -> Function
Function JSVal
callback)
rAFSubElapsed
:: Double
-> action
-> Sub action
rAFSubElapsed :: forall action. Double -> action -> Sub action
rAFSubElapsed Double
interval action
action Sink action
sink = IO (IORef JSVal) -> (IORef JSVal -> IO ()) -> Sub action
forall a b action. IO a -> (a -> IO b) -> Sub action
createSub IO (IORef JSVal)
acquire IORef JSVal -> IO ()
release Sink action
sink
where
acquire :: IO (IORef JSVal)
acquire = do
IORef JSVal
cbRef <- JSVal -> IO (IORef JSVal)
forall a. a -> IO (IORef a)
newIORef ([Char] -> JSVal
forall a. HasCallStack => [Char] -> a
error [Char]
"rAFSubElapsed: uninitialized, impossible")
let go :: Double -> Double -> IO ()
go Double
lastT Double
elap = do
JSVal
cb <- (JSVal -> IO ()) -> IO JSVal
syncCallback1 ((JSVal -> IO ()) -> IO JSVal) -> (JSVal -> IO ()) -> IO JSVal
forall a b. (a -> b) -> a -> b
$ \JSVal
jsval -> do
Double
t <- JSVal -> IO Double
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked JSVal
jsval
let dt :: Double
dt = if Double
lastT Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 then Double
0 else Double -> Double -> Double
forall a. Ord a => a -> a -> a
min Double
interval (Double
t Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
lastT)
newElap :: Double
newElap = Double
elap Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
dt
if Double
newElap Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
interval
then Sink action
sink action
action IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Double -> Double -> IO ()
go Double
t (Double
newElap Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
interval)
else Double -> Double -> IO ()
go Double
t Double
newElap
IORef JSVal -> JSVal -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef JSVal
cbRef JSVal
cb
IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (JSVal -> IO Int
requestAnimationFrame JSVal
cb)
Double -> Double -> IO ()
go Double
0 Double
0
IORef JSVal -> IO (IORef JSVal)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure IORef JSVal
cbRef
release :: IORef JSVal -> IO ()
release IORef JSVal
cbRef = Function -> IO ()
freeFunction (Function -> IO ()) -> (JSVal -> Function) -> JSVal -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSVal -> Function
Function (JSVal -> IO ()) -> IO JSVal -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef JSVal -> IO JSVal
forall a. IORef a -> IO a
readIORef IORef JSVal
cbRef