module Bluefin.Capability.Request
  ( -- | @Request@ allows to yield values and await the result. You
    -- might want to start with "Bluefin.Capability.Yield", which is
    -- the most common way to use @Request@s.

    -- ** Prompt finalization/resource safety

    -- | Bluefin
    -- t'Bluefin.Capability.Yield.Yield' \/ t'Bluefin.Capability.Await.Await' \/ t'Bluefin.Capability.Request.Request'
    -- computations have much better resource safety properties than
    -- Conduit and Pipes.  You can use
    -- @Bluefin.Eff.'Bluefin.Eff.bracket'@ within a streaming
    -- computation and the acquired resource is guaranteed to be
    -- released and the end of the bracket, rather than at the end of
    -- the @ResourceT@ scope as it is the case in Conduit and Pipes.
    -- See the blog post [Bluefin streams finalize
    -- promptly](https://h2.jaguarpaw.co.uk/posts/bluefin-streams-finalize-promptly/)
    -- for more details.

    -- ** Running coroutines that communicate via @Request@s

    -- | Bluefin operations can be executed as coroutines using
    --  'connectRequests' ([Wikipedia
    --  suggests](https://en.wikipedia.org/wiki/Coroutine#Definition_and_types)
    --  that such coroutines are "second-class stackful coroutines").
    --  Two coroutines run in this way communicate synchronously by
    --  using @Request@s to interact with a bi-directional
    --  channel. This means that such coroutines are often run
    --  exclusively for what they communicate via this channel, not
    --  for their return value.
    --
    -- @Request@s used in this way work a bit like UNIX pipes: there
    -- is a downstream consumer and an upstream generator. For every
    -- pair of such communicating coroutines there are two ends,
    -- represented with the capabilities @Request a b@ and @Request b
    -- a@. The first parameter to @Request@ is the type that can be
    -- /sent from/ that end, while the second parameter is the type
    -- that will subsequently be /received by/ that end. This explains
    -- the symmetry in the capabilities: what one end sends the other
    -- receives. The implication is that upstream and downstream
    -- exchange messages with each other at the same
    -- time. Additionally, there is a clear order of communication
    -- from the start (in Bluefin, communication is started by
    -- upstream).
    --
    -- 'request' is the only effectful operation required: a @Request
    -- a b@ capability that represents one end of a channel sends @a@s
    -- and receives a @b@s. For many use cases, upstream does not need
    -- to know anything from downstream (dually: downstream does not
    -- need to communicate anything to upstream) except that
    -- downstream is making a new request, so the capabilities that
    -- describe most channels are \"@Request a ()@\" and \"@Request ()
    -- a@\". Bluefin provides synonyms for these:
    -- @'Bluefin.Capability.Yield.Yield' a@ and
    -- @'Bluefin.Capability.Await.Await' a@, respectively. The
    -- specializations of @request@ for @Yield@ and @Await@ are called
    -- 'Bluefin.Capability.Yield.yield' and
    -- 'Bluefin.Capability.Await.await'.  Coroutines that send data in
    -- only one direction like this can be created using 'awaitYield'.
    --
    -- Because the message exchange occurs synchronously, when yielding,
    -- the upstream will block until the downstream awaits. The converse
    -- is also true: when downstream awaits, it will block until upstream
    -- yields.
    --
    -- Any Bluefin effectful operation that takes a @Request@
    -- capability as an argument can be run as coroutine using
    -- 'connectRequests' by providing a second effectful operation
    -- as its counterpart on the other end of the channel.
    --
    -- For simple applications one may not need @connectRequests@ at
    -- all, because specific handlers are already provided by
    -- Bluefin. See the \"Handlers\" sections of the
    -- "Bluefin.Capability.Yield" and "Bluefin.Capability.Await"
    -- modules.

    -- * Capability
    Request,

    -- * Handlers
    forEach,
    connectRequests,

    -- * Effectful operations
    request,
  )
where

import Bluefin.Internal