packages feed

unfork-1.0.0.0: Unfork/Async/WithResult/STM.hs

{-

STM, asynchronous, with task results available

To make task results available, we maintain a queue that contains not only each the task itself, but also a TVar to store its result. Each step of the queue loop runs the action and then places the result into the TVar.

-}

module Unfork.Async.WithResult.STM
    (
        unforkAsyncSTM,
    )
    where

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

import Prelude (IO, Maybe (..), pure)

import Control.Monad.STM (STM, atomically)

import qualified Control.Concurrent.STM as STM

{- |

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

    Related functions:

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

-}

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

unforkAsyncSTM action =
    unforkAsync Unfork{ unforkedAction, executeOneTask }
  where
    unforkedAction ctx arg = do
        resultVar <- STM.newTVar Nothing
        enqueue ctx Task{ arg, resultVar }
        pure (STM.readTVar resultVar)

    executeOneTask Task{ arg, resultVar } = do
        b <- action arg
        atomically (STM.writeTVar resultVar (Just b))