-- | 'ReactHandle's.
--
-- Sometimes it is beneficial to give control to an external main loop,
-- for example OpenGL or a hardware-clocked audio server like JACK.
-- This module makes Dunai compatible with external main loops.

module Data.MonadicStreamFunction.ReactHandle where

-- External
import Control.Monad.IO.Class
import Data.IORef

-- Internal
import Data.MonadicStreamFunction
import Data.MonadicStreamFunction.InternalCore


-- | A storage for the current state of an 'MSF'.
-- The 'MSF' may not require input or produce output data,
-- all such data must be handled through side effects
-- (such as wormholes).
type ReactHandle m = IORef (MSF m () ())


-- | Needs to be called before the external main loop is dispatched.
reactInit :: MonadIO m => MSF m () () -> m (ReactHandle m)
reactInit :: MSF m () () -> m (ReactHandle m)
reactInit = IO (ReactHandle m) -> m (ReactHandle m)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ReactHandle m) -> m (ReactHandle m))
-> (MSF m () () -> IO (ReactHandle m))
-> MSF m () ()
-> m (ReactHandle m)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MSF m () () -> IO (ReactHandle m)
forall a. a -> IO (IORef a)
newIORef


-- | The callback that needs to be called by the external loop at every cycle.
react :: MonadIO m => ReactHandle m -> m ()
react :: ReactHandle m -> m ()
react ReactHandle m
handle = do
  MSF m () ()
msf <- IO (MSF m () ()) -> m (MSF m () ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (MSF m () ()) -> m (MSF m () ()))
-> IO (MSF m () ()) -> m (MSF m () ())
forall a b. (a -> b) -> a -> b
$ ReactHandle m -> IO (MSF m () ())
forall a. IORef a -> IO a
readIORef ReactHandle m
handle
  (()
_, MSF m () ()
msf') <- MSF m () () -> () -> m ((), MSF m () ())
forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m () ()
msf ()
  IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ ReactHandle m -> MSF m () () -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef ReactHandle m
handle MSF m () ()
msf'