module Engine.Events
  ( Sink(..)
  , spawn
  , registerMany
  ) where

import RIO

import UnliftIO.Resource (MonadResource, ReleaseKey)
import UnliftIO.Resource qualified as Resource

import Engine.Events.Sink (MonadSink, Sink)
import Engine.Events.Sink qualified as Sink

spawn
  :: MonadSink st m
  => (event -> m ())
  -> [Sink event st -> m ReleaseKey]
  -> m (ReleaseKey, Sink event st)
spawn :: forall st (m :: * -> *) event.
MonadSink st m =>
(event -> m ())
-> [Sink event st -> m ReleaseKey] -> m (ReleaseKey, Sink event st)
spawn event -> m ()
handleEvent [Sink event st -> m ReleaseKey]
sources = do
  (ReleaseKey
sinkKey, Sink event st
sink) <- forall rs (m :: * -> *) event.
MonadSink rs m =>
(event -> m ()) -> m (ReleaseKey, Sink event rs)
Sink.spawn event -> m ()
handleEvent

  ReleaseKey
key <- forall (m :: * -> *).
MonadResource m =>
[m ReleaseKey] -> m ReleaseKey
registerMany forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) a. Applicative f => a -> f a
pure ReleaseKey
sinkKey forall a. a -> [a] -> [a]
:
    forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a -> b) -> a -> b
$ Sink event st
sink) [Sink event st -> m ReleaseKey]
sources

  pure (ReleaseKey
key, Sink event st
sink)

registerMany
  :: MonadResource m
  => [m ReleaseKey]
  -> m ReleaseKey
registerMany :: forall (m :: * -> *).
MonadResource m =>
[m ReleaseKey] -> m ReleaseKey
registerMany [m ReleaseKey]
actions =
  forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
sequenceA [m ReleaseKey]
actions forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    forall (m :: * -> *). MonadResource m => IO () -> m ReleaseKey
Resource.register forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ forall (m :: * -> *). MonadIO m => ReleaseKey -> m ()
Resource.release