-- | Description: Polysemy Effects for Concurrency
module Polysemy.Conc (
  -- * Introduction
  -- $intro

  -- * Queues
  -- $queue
  Queue,
  QueueResult,

  -- ** Interpreters
  interpretQueueTBM,
  interpretQueueTB,
  interpretQueueListReadOnlyAtomic,
  interpretQueueListReadOnlyAtomicWith,
  interpretQueueListReadOnlyState,
  interpretQueueListReadOnlyStateWith,

  -- ** Combinators
  resultToMaybe,
  loop,
  loopOr,

  -- * MVars
  -- $mvar
  Sync,
  SyncRead,
  ScopedSync,

  -- ** Interpreters
  interpretSync,
  interpretSyncAs,
  withSync,
  interpretScopedSync,
  interpretScopedSyncAs,
  syncRead,

  -- * Lock
  Lock,
  lock,
  lockOr,
  lockOrSkip,
  lockOrSkip_,

  -- ** Interpreters
  interpretLockReentrant,
  interpretLockPermissive,

  -- * Semaphores
  Semaphore,

  -- ** Interpreters
  interpretSemaphoreQ,
  interpretSemaphoreT,

  -- * Gate
  Gate,
  Gates,

  -- ** Interpreters
  interpretGates,
  interpretGate,

  -- * Racing
  -- $race
  Race,
  race,
  race_,
  timeout,
  timeout_,
  timeoutAs,
  timeoutAs_,
  timeoutU,
  timeoutMaybe,
  timeoutStop,
  retrying,
  retryingWithError,

  -- ** Interpreters
  interpretRace,

  -- * Event Channels
  Events,
  Consume,
  publish,
  consume,
  subscribe,
  subscribeGated,
  subscribeAsync,
  subscribeWhile,
  subscribeWhileGated,
  subscribeWhileAsync,
  subscribeLoop,
  subscribeLoopGated,
  subscribeLoopAsync,
  subscribeFind,
  subscribeFirstJust,
  subscribeElem,
  consumeWhile,
  consumeLoop,
  consumeFind,
  consumeFirstJust,
  consumeElem,
  EventConsumer,

  -- ** Interpreters
  interpretEventsChan,

  -- * Exceptions
  Critical,

  -- ** Interpreters
  interpretCritical,
  interpretCriticalNull,

  -- * Masking
  Mask,
  MaskMode (..),
  UninterruptibleMask,
  mask,
  uninterruptibleMask,
  restore,
  Restoration,

  -- * Interpreters
  interpretMaskFinal,
  interpretUninterruptibleMaskFinal,
  interpretMaskPure,
  interpretUninterruptibleMaskPure,

  -- * Monitoring
  Monitor,
  monitor,
  withMonitor,
  restart,
  Restart,
  RestartingMonitor,
  ScopedMonitor,

  -- ** Interpreters
  interpretMonitorRestart,
  interpretMonitorPure,
  monitorClockSkew,
  ClockSkewConfig (ClockSkewConfig),
  clockSkewConfig,

  -- * Other Combinators
  ConcStack,
  runConc,
  interpretAtomic,
  withAsyncBlock,
  withAsync,
  withAsync_,
  scheduleAsync,
  scheduleAsyncIO,
  withAsyncGated,
  withAsyncGated_,
) where

import Prelude hiding (
  Scoped,
  Scoped_,
  interpretScoped,
  interpretScopedAs,
  interpretScopedH,
  interpretScopedH',
  interpretScopedWith,
  interpretScopedWithH,
  interpretScopedWith_,
  rescope,
  runScoped,
  runScopedAs,
  scoped,
  scoped_,
  )

import Polysemy.Conc.Async (
  scheduleAsync,
  scheduleAsyncIO,
  withAsync,
  withAsyncBlock,
  withAsyncGated,
  withAsyncGated_,
  withAsync_,
  )
import Polysemy.Conc.AtomicState (interpretAtomic)
import Polysemy.Conc.Data.QueueResult (QueueResult)
import Polysemy.Conc.Effect.Critical (Critical)
import Polysemy.Conc.Effect.Events (Consume, Events, consume, publish, subscribe)
import Polysemy.Conc.Effect.Gate (Gate, Gates)
import Polysemy.Conc.Effect.Lock (Lock, lock, lockOr, lockOrSkip, lockOrSkip_)
import Polysemy.Conc.Effect.Mask (Mask, MaskMode (..), Restoration, UninterruptibleMask, mask, restore, uninterruptibleMask)
import Polysemy.Conc.Effect.Monitor (Monitor, Restart, RestartingMonitor, ScopedMonitor, monitor, restart, withMonitor)
import Polysemy.Conc.Effect.Queue (Queue)
import Polysemy.Conc.Effect.Race (Race, race, timeout)
import Polysemy.Conc.Effect.Semaphore (Semaphore)
import Polysemy.Conc.Effect.Sync (ScopedSync, Sync)
import Polysemy.Conc.Effect.SyncRead (SyncRead)
import Polysemy.Conc.Events (
  consumeElem,
  consumeFind,
  consumeFirstJust,
  consumeLoop,
  consumeWhile,
  subscribeAsync,
  subscribeElem,
  subscribeFind,
  subscribeFirstJust,
  subscribeGated,
  subscribeLoop,
  subscribeLoopAsync,
  subscribeLoopGated,
  subscribeWhile,
  subscribeWhileAsync,
  subscribeWhileGated,
  )
import Polysemy.Conc.Interpreter.Critical (interpretCritical, interpretCriticalNull)
import Polysemy.Conc.Interpreter.Events (EventConsumer, interpretEventsChan)
import Polysemy.Conc.Interpreter.Gate (interpretGate, interpretGates)
import Polysemy.Conc.Interpreter.Lock (interpretLockPermissive, interpretLockReentrant)
import Polysemy.Conc.Interpreter.Mask (
  interpretMaskFinal,
  interpretMaskPure,
  interpretUninterruptibleMaskFinal,
  interpretUninterruptibleMaskPure,
  )
import Polysemy.Conc.Interpreter.Monitor (interpretMonitorPure, interpretMonitorRestart)
import Polysemy.Conc.Interpreter.Queue.Pure (
  interpretQueueListReadOnlyAtomic,
  interpretQueueListReadOnlyAtomicWith,
  interpretQueueListReadOnlyState,
  interpretQueueListReadOnlyStateWith,
  )
import Polysemy.Conc.Interpreter.Queue.TB (interpretQueueTB)
import Polysemy.Conc.Interpreter.Queue.TBM (interpretQueueTBM)
import Polysemy.Conc.Interpreter.Race (interpretRace)
import Polysemy.Conc.Interpreter.Semaphore (interpretSemaphoreQ, interpretSemaphoreT)
import Polysemy.Conc.Interpreter.Stack (ConcStack, runConc)
import Polysemy.Conc.Interpreter.Sync (interpretScopedSync, interpretScopedSyncAs, interpretSync, interpretSyncAs)
import Polysemy.Conc.Interpreter.SyncRead (syncRead)
import Polysemy.Conc.Monitor (ClockSkewConfig (ClockSkewConfig), clockSkewConfig, monitorClockSkew)
import Polysemy.Conc.Queue (loop, loopOr)
import Polysemy.Conc.Queue.Result (resultToMaybe)
import Polysemy.Conc.Race (race_, timeoutAs, timeoutAs_, timeoutMaybe, timeoutStop, timeoutU, timeout_)
import Polysemy.Conc.Retry (retrying, retryingWithError)
import Polysemy.Conc.Sync (withSync)

-- $intro
-- This library provides an assortment of tools for concurrency-related tasks:
--
-- - [STM queues](#queue)
-- - [MVars](#mvar)
-- - [Racing](#race)
-- - [Signal handling](#signal)
-- - [Masking](#mask)

-- $queue
-- #queue#

-- $mvar
-- #mvar#
-- An 'Control.Concurrent.MVar' is abstracted as 'Sync' since it can be used to synchronize threads.

-- $race
-- #race#
-- Racing works like this:
--
-- @
-- prog =
--  Polysemy.Conc.race (httpRequest "hackage.haskell.org") (readFile "\/path\/to\/file") >>= \\case
--    Left _ -> putStrLn "hackage was faster"
--    Right _ -> putStrLn "file was faster"
-- @
--
-- When the first thunk finishes, the other will be killed.

-- $mask
-- #mask#
-- The 'Mask' effect uses the 'Polysemy.Scoped' pattern with 'MaskMode' as the scope parameter.
-- 'mask' and 'uninterruptibleMask' are convenience functions that pass 'Interruptible' or 'Uninterruptible' to
-- 'Polysemy.scoped'.
--
-- Usage is straightforward:
--
-- @
-- prog :: Member Mask r
-- prog =
--  mask do
--    doMaskedThing
--    restore do
--      doUnmaskedThing
--    doMaskedThing
-- @