module Engine.DataRecycler where

import RIO

import Control.Concurrent.Chan.Unagi qualified as Unagi

data DataRecycler a = DataRecycler
  { forall a. DataRecycler a -> DumpResource a
drDump :: DumpResource a
    {- ^
      Filled with resources which aren't destroyed after finishing a frame,
      but instead are used by another frame which executes after that one is
      retired, (taken from ghRecycleOut)

      Make sure not to pass any resources which were created with a frame-only
      scope however!
    -}
  , forall a. DataRecycler a -> WaitResource a
drWait :: WaitResource a
    -- ^ The resources of prior frames waiting to be taken
  }

type DumpResource a = a -> IO ()

type WaitResource a = IO (Either (IO a) a)

new :: MonadIO m => m (DataRecycler a)
new :: forall (m :: * -> *) a. MonadIO m => m (DataRecycler a)
new = do
  (InChan a
recycleWrite, OutChan a
recycleRead) <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a. IO (InChan a, OutChan a)
Unagi.newChan
  forall (f :: * -> *) a. Applicative f => a -> f a
pure DataRecycler
    { $sel:drDump:DataRecycler :: DumpResource a
drDump = forall a. InChan a -> a -> IO ()
Unagi.writeChan InChan a
recycleWrite
    , $sel:drWait:DataRecycler :: WaitResource a
drWait = do
        (Element a
tryOp, IO a
blockOp) <- forall a. OutChan a -> IO (Element a, IO a)
Unagi.tryReadChan OutChan a
recycleRead
        Maybe a
res <- forall a. Element a -> IO (Maybe a)
Unagi.tryRead Element a
tryOp
        pure $ forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a b. a -> Either a b
Left IO a
blockOp) forall a b. b -> Either a b
Right Maybe a
res
    }