content: -- | `ki` is a lightweight structured concurrency library.
  --
  -- For a variant of this API generalized to
  -- @<https://hackage.haskell.org/package/unliftio-core/docs/Control-Monad-IO-Unlift.html#t:MonadUnliftIO MonadUnliftIO>@,
  -- see @<https://hackage.haskell.org/package/ki-unlifted ki-unlifted>@.
  --
  -- Remember to link your program with @-threaded@ to use the threaded runtime!
  module Ki
    ( -- * Introduction
      -- $introduction
  
      -- * Core API
      Scope,
      Thread,
      scoped,
      fork,
      forkTry,
      await,
      awaitAll,
  
      -- * Extended API
      fork_,
      forkWith,
      forkWith_,
      forkTryWith,
  
      -- ** Thread options
      ThreadOptions (..),
      defaultThreadOptions,
      ThreadAffinity (..),
  
      -- ** Byte count
      ByteCount,
      kilobytes,
      megabytes,
    )
  where
  
  import Ki.Internal.ByteCount (ByteCount, kilobytes, megabytes)
  import Ki.Internal.Scope
    ( Scope,
      awaitAll,
      fork,
      forkTry,
      forkTryWith,
      forkWith,
      forkWith_,
      fork_,
      scoped,
    )
  import Ki.Internal.Thread (Thread, await)
  import Ki.Internal.ThreadAffinity (ThreadAffinity (..))
  import Ki.Internal.ThreadOptions (ThreadOptions (..), defaultThreadOptions)
  
  -- $introduction
  --
  -- Structured concurrency is a paradigm of concurrent programming in which a lexical scope delimits the lifetime of each
  -- thread. Threads therefore form a "call tree" hierarchy in which no child can outlive its parent.
  --
  -- Exceptions are propagated promptly from child to parent and vice-versa:
  --
  --     * If an exception is raised in a child thread, the child raises the same exception in its parent, then
  --       terminates.
  --
  --     * If an exception is raised in a parent thread, the parent first raises an exception in all of its living
  --       children, waits for them to terminate, then re-raises the original exception.
  --
  -- All together, this library:
  --
  --     * Guarantees the absence of "ghost threads" (/i.e./ threads that accidentally continue to run alongside the main
  --       thread after the function that spawned them returns).
  --
  --     * Performs prompt, bidirectional exception propagation when an exception is raised anywhere in the call tree.
  --
  --     * Provides a safe and flexible API that can be used directly, or with which higher-level concurrency patterns can
  --       be built on top, such as worker queues, pub-sub pipelines, and supervision trees.
  --
  -- For a longer introduction to structured concurrency, including an educative analogy to structured programming, please
  -- read Nathaniel J. Smith's blog post,
  -- <https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ "Notes on structured concurrency, or: Go statement considered harmful">.
  --
  -- ==== __👉 Quick start examples__
  --
  -- * Perform two actions concurrently, and wait for both of them to complete.
  --
  --     @
  --     concurrently :: IO a -> IO b -> IO (a, b)
  --     concurrently action1 action2 =
  --       Ki.'Ki.scoped' \\scope -> do
  --         thread1 <- Ki.'Ki.fork' scope action1
  --         result2 <- action2
  --         result1 <- atomically (Ki.'Ki.await' thread1)
  --         pure (result1, result2)
  --     @
  --
  -- * Perform two actions concurrently, and when the first action terminates, stop executing the other.
  --
  --     @
  --     race :: IO a -> IO a -> IO a
  --     race action1 action2 =
  --       Ki.'Ki.scoped' \\scope -> do
  --         resultVar \<- newEmptyMVar
  --         _ \<- Ki.'Ki.fork' scope (action1 \>>= tryPutMVar resultVar)
  --         _ \<- Ki.'Ki.fork' scope (action2 \>>= tryPutMVar resultVar)
  --         takeMVar resultVar
  --     @
  