{-

I/O, asynchronous, with task results available

Similar to its STM counterpart, but uses MVar instead of TVar.

-}

module Unfork.Async.WithResult.IO
    (
        unforkAsyncIO,
        Future, await, poll,
    )
    where

import Unfork.Async.Core
import Unfork.Async.WithResult.Future
import Unfork.Async.WithResult.Task

import Prelude (IO, pure)

import Control.Monad.STM (atomically)

import qualified Control.Concurrent.MVar as MVar

{- |

    Unforks an action, with the new action's asynchronous result available as @('IO' ('Future' result))@

    Related functions:

      - Use 'Unfork.unforkAsyncIO_' if you do not need to know when the action has completed or obtain its result value
      - Use 'Unfork.unforkAsyncSTM' if you need the composability of 'Control.Monad.STM.STM'

-}

unforkAsyncIO ::
    (task -> IO result) -- ^ Action that needs to be run serially
    -> ((task -> IO (Future result)) -> IO conclusion) -- ^ Continuation with the unforked action
    -> IO conclusion

unforkAsyncIO :: (task -> IO result)
-> ((task -> IO (Future result)) -> IO conclusion) -> IO conclusion
unforkAsyncIO task -> IO result
action =
    Unfork task (IO (Future result))
-> ((task -> IO (Future result)) -> IO conclusion) -> IO conclusion
forall a c b. Unfork a c -> ((a -> c) -> IO b) -> IO b
unforkAsync Unfork :: forall a c q. (Ctx q -> a -> c) -> (q -> IO ()) -> Unfork a c
Unfork{ Ctx (Task task (MVar result)) -> task -> IO (Future result)
forall a result.
Ctx (Task a (MVar result)) -> a -> IO (Future result)
unforkedAction :: Ctx (Task task (MVar result)) -> task -> IO (Future result)
unforkedAction :: forall a result.
Ctx (Task a (MVar result)) -> a -> IO (Future result)
unforkedAction, Task task (MVar result) -> IO ()
executeOneTask :: Task task (MVar result) -> IO ()
executeOneTask :: Task task (MVar result) -> IO ()
executeOneTask }
  where
    unforkedAction :: Ctx (Task a (MVar result)) -> a -> IO (Future result)
unforkedAction Ctx (Task a (MVar result))
ctx a
arg = do
        MVar result
resultVar <- IO (MVar result)
forall a. IO (MVar a)
MVar.newEmptyMVar
        STM () -> IO ()
forall a. STM a -> IO a
atomically (Ctx (Task a (MVar result)) -> Task a (MVar result) -> STM ()
forall q. Ctx q -> q -> STM ()
enqueue Ctx (Task a (MVar result))
ctx Task :: forall a b. a -> b -> Task a b
Task{ a
arg :: a
arg :: a
arg, MVar result
resultVar :: MVar result
resultVar :: MVar result
resultVar })
        Future result -> IO (Future result)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MVar result -> Future result
forall result. MVar result -> Future result
Future MVar result
resultVar)
    executeOneTask :: Task task (MVar result) -> IO ()
executeOneTask Task{ task
arg :: task
arg :: forall a b. Task a b -> a
arg, MVar result
resultVar :: MVar result
resultVar :: forall a b. Task a b -> b
resultVar } = do
          result
b <- task -> IO result
action task
arg
          MVar result -> result -> IO ()
forall a. MVar a -> a -> IO ()
MVar.putMVar MVar result
resultVar result
b