"use strict"
var __createBinding =
  (this && this.__createBinding) ||
  (Object.create
    ? function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        Object.defineProperty(o, k2, {
          enumerable: true,
          get: function () {
            return m[k]
          }
        })
      }
    : function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        o[k2] = m[k]
      })
var __setModuleDefault =
  (this && this.__setModuleDefault) ||
  (Object.create
    ? function (o, v) {
        Object.defineProperty(o, "default", { enumerable: true, value: v })
      }
    : function (o, v) {
        o["default"] = v
      })
var __importStar =
  (this && this.__importStar) ||
  function (mod) {
    if (mod && mod.__esModule) return mod
    var result = {}
    if (mod != null)
      for (var k in mod)
        if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
          __createBinding(result, mod, k)
    __setModuleDefault(result, mod)
    return result
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.createQueue =
  exports.createQueue_ =
  exports.unsafeCreateQueue =
  exports.makeBoundedQueue =
  exports.BackPressureStrategy =
  exports.managedUse_ =
  exports.managedFork =
  exports.releaseMapReleaseAll =
  exports.fiberWaitAll =
  exports.fiberJoinAll =
  exports.collectAllSuccessesParN =
  exports.collectAllSuccessesParN_ =
  exports.collectAllSuccessesPar =
  exports.collectAllSuccesses =
  exports.collectAllWithParN =
  exports.collectAllWithParN_ =
  exports.collectAllWithPar =
  exports.collectAllWithPar_ =
  exports.collectAllWith =
  exports.collectAllWith_ =
  exports.collectAllUnitParN_ =
  exports.collectAllUnitParN =
  exports.collectAllUnitPar =
  exports.collectAllUnit =
  exports.collectAllParN_ =
  exports.collectAllParN =
  exports.collectAllPar =
  exports.collectAll =
  exports.forEachExec =
  exports.forEachExec_ =
  exports.forEachParN =
  exports.forEachParN_ =
  exports.forEachUnitParN =
  exports.forEachUnitParN_ =
  exports.forEachPar =
  exports.forEachPar_ =
  exports.forEachUnitPar =
  exports.forkManaged =
  exports.forEachUnitPar_ =
  exports.forEachUnit =
  exports.forEachUnit_ =
  exports.forEach =
  exports.forEach_ =
    void 0
// tracing: off
const cause = __importStar(require("../Cause"))
const ChunkFilter = __importStar(require("../Collections/Immutable/Chunk/api/filter"))
const ChunkFilterMap = __importStar(
  require("../Collections/Immutable/Chunk/api/filterMap")
)
const ChunkForEach = __importStar(require("../Collections/Immutable/Chunk/api/forEach"))
const ChunkIndexWhere = __importStar(
  require("../Collections/Immutable/Chunk/api/indexWhere")
)
const ChunkSplitAt = __importStar(require("../Collections/Immutable/Chunk/api/splitAt"))
const ChunkZip = __importStar(require("../Collections/Immutable/Chunk/api/zip"))
const Chunk = __importStar(require("../Collections/Immutable/Chunk/core"))
const L = __importStar(require("../Collections/Immutable/List/core"))
const Tp = __importStar(require("../Collections/Immutable/Tuple"))
const Ex = __importStar(require("../Exit"))
const interrupt_1 = require("../Fiber/interrupt")
const Function_1 = require("../Function")
const I = __importStar(require("../Iterable"))
const deps_core_1 = require("../Managed/deps-core")
const managed_1 = require("../Managed/managed")
const add_1 = require("../Managed/ReleaseMap/add")
const Exited_1 = require("../Managed/ReleaseMap/Exited")
const makeReleaseMap_1 = require("../Managed/ReleaseMap/makeReleaseMap")
const O = __importStar(require("../Option"))
const promise = __importStar(require("../Promise"))
const Q = __importStar(require("../Queue/core"))
const xqueue_1 = require("../Queue/xqueue")
const AtomicBoolean_1 = require("../Support/AtomicBoolean")
const MutableQueue_1 = require("../Support/MutableQueue")
const asUnit = __importStar(require("./asUnit"))
const bracket = __importStar(require("./bracket"))
const bracketExit_1 = require("./bracketExit")
const catchAll = __importStar(require("./catchAll"))
const core = __importStar(require("./core"))
const coreScope = __importStar(require("./core-scope"))
const Do = __importStar(require("./do"))
const done_1 = require("./done")
const ensuring = __importStar(require("./ensuring"))
const environment_1 = require("./environment")
const Ref = __importStar(require("./excl-deps-ref"))
const ExecutionStrategy_1 = require("./ExecutionStrategy")
const fiberId = __importStar(require("./fiberId"))
const flatten = __importStar(require("./flatten"))
const ifM = __importStar(require("./ifM"))
const interruption = __importStar(require("./interruption"))
const map = __importStar(require("./map"))
const provideSome_1 = require("./provideSome")
const tap = __importStar(require("./tap"))
const tapCause = __importStar(require("./tapCause"))
const toManaged_1 = require("./toManaged")
const whenM = __importStar(require("./whenM"))
const zips = __importStar(require("./zips"))
/**
 * Applies the function `f` to each element of the `Iterable<A>` and
 * returns the results in a new `readonly B[]`.
 *
 * For a parallel version of this method, see `forEachPar`.
 * If you do not need the results, see `forEachUnit` for a more efficient implementation.
 */
function forEach_(as, f, __trace) {
  return core.suspend(() => {
    const acc = []
    return map.map_(
      forEachUnit_(as, (a) =>
        map.map_(f(a), (b) => {
          acc.push(b)
        })
      ),
      () => Chunk.from(acc)
    )
  }, __trace)
}
exports.forEach_ = forEach_
/**
 * Applies the function `f` to each element of the `Iterable<A>` and
 * returns the results in a new `readonly B[]`.
 *
 * For a parallel version of this method, see `forEachPar`.
 * If you do not need the results, see `forEachUnit` for a more efficient implementation.
 *
 * @dataFirst forEach_
 */
function forEach(f, __trace) {
  return (as) => forEach_(as, f, __trace)
}
exports.forEach = forEach
function forEachUnitLoop(iterator, f) {
  const next = iterator.next()
  return next.done
    ? core.unit
    : core.chain_(f(next.value), () => forEachUnitLoop(iterator, f))
}
/**
 * Applies the function `f` to each element of the `Iterable<A>` and runs
 * produced effects sequentially.
 *
 * Equivalent to `asUnit(forEach(as, f))`, but without the cost of building
 * the list of results.
 */
function forEachUnit_(as, f, __trace) {
  return core.suspend(() => forEachUnitLoop(as[Symbol.iterator](), f), __trace)
}
exports.forEachUnit_ = forEachUnit_
/**
 * Applies the function `f` to each element of the `Iterable<A>` and runs
 * produced effects sequentially.
 *
 * Equivalent to `asUnit(forEach(as, f))`, but without the cost of building
 * the list of results.
 *
 * @dataFirst forEachUnit_
 */
function forEachUnit(f, __trace) {
  return (as) => forEachUnit_(as, f, __trace)
}
exports.forEachUnit = forEachUnit
/**
 * Applies the function `f` to each element of the `Iterable<A>` and runs
 * produced effects in parallel, discarding the results.
 *
 * For a sequential version of this method, see `forEach_`.
 *
 * Optimized to avoid keeping full tree of effects, so that method could be
 * able to handle large input sequences.
 * Behaves almost like this code:
 *
 * Additionally, interrupts all effects on any failure.
 */
function forEachUnitPar_(as, f, __trace) {
  const collection = L.from(as)
  const size = L.size(collection)
  if (L.isEmpty(collection)) {
    return core.unit
  }
  return core.suspend(
    () =>
      asUnit.asUnit(
        tap.tap_(
          Do.let_(
            Do.bind_(
              Do.let_(
                Do.let_(
                  Do.let_(
                    Do.bind_(
                      Do.bind_(
                        Do.bind_(
                          Do.bind_(Do.do, "parentId", () => fiberId.fiberId),
                          "causes",
                          () => Ref.makeRef(cause.empty)
                        ),
                        "result",
                        () => promise.make()
                      ),
                      "status",
                      () => Ref.makeRef(Tp.tuple(0, 0, false))
                    ),
                    "startTask",
                    ({ status }) =>
                      Ref.modify_(status, ({ tuple: [started, done, failing] }) => {
                        if (failing) {
                          return Tp.tuple(false, Tp.tuple(started, done, failing))
                        }
                        return Tp.tuple(true, Tp.tuple(started + 1, done, failing))
                      })
                  ),
                  "startFailure",
                  ({ result, status }) =>
                    zips.zipRight_(
                      Ref.update_(status, ({ tuple: [started, done, _] }) =>
                        Tp.tuple(started, done, true)
                      ),
                      promise.fail(undefined)(result)
                    )
                ),
                "task",
                ({ causes, parentId, result, startFailure, startTask, status }) =>
                  (a) =>
                    interruption.uninterruptible(
                      ifM.ifM_(
                        startTask,
                        () =>
                          ensuring.ensuring_(
                            tapCause.tapCause_(
                              interruption.interruptible(core.suspend(() => f(a))),
                              (c) =>
                                zips.zipRight_(
                                  Ref.update_(causes, (_) => cause.both(_, c)),
                                  startFailure
                                )
                            ),
                            (() => {
                              const isComplete = Ref.modify_(
                                status,
                                ({ tuple: [started, done, failing] }) => {
                                  const newDone = done + 1
                                  return Tp.tuple(
                                    (failing ? started : size) === newDone,
                                    Tp.tuple(started, newDone, failing)
                                  )
                                }
                              )
                              return whenM.whenM_(
                                promise.succeed(undefined)(result),
                                isComplete
                              )
                            })()
                          ),
                        () =>
                          Ref.update_(causes, (_) =>
                            cause.both(_, cause.interrupt(parentId))
                          )
                      )
                    )
              ),
              "fibers",
              ({ task }) =>
                coreScope.transplant((graft) =>
                  forEach_(collection, (a) => core.fork(graft(task(a))))
                )
            ),
            "interrupter",
            ({ fibers, parentId, result }) =>
              forkManaged(
                catchAll.catchAll_(promise.await(result), () =>
                  core.chain_(
                    forEach_(fibers, (_) => core.fork(_.interruptAs(parentId))),
                    fiberJoinAll
                  )
                )
              )
          ),
          ({ causes, fibers, interrupter, result }) =>
            managedUse_(interrupter, () =>
              whenM.whenM_(
                zips.zipRight_(
                  promise.fail(undefined)(result),
                  core.chain_(causes.get, core.halt)
                ),
                map.map_(
                  forEach_(fibers, (_) => _.await),
                  (_) =>
                    ChunkIndexWhere.indexWhere_(_, (ex) => !Ex.succeeded(ex)) !== -1
                )
              )
            )
        )
      ),
    __trace
  )
}
exports.forEachUnitPar_ = forEachUnitPar_
/**
 * Forks the fiber in a `Managed`. Using the `Managed` value will
 * execute the effect in the fiber, while ensuring its interruption when
 * the effect supplied to `use` completes.
 */
function forkManaged(self, __trace) {
  return managedFork((0, toManaged_1.toManaged)(self), __trace)
}
exports.forkManaged = forkManaged
/**
 * Applies the function `f` to each element of the `Iterable<A>` and runs
 * produced effects in parallel, discarding the results.
 *
 * For a sequential version of this method, see `forEach_`.
 *
 * Optimized to avoid keeping full tree of effects, so that method could be
 * able to handle large input sequences.
 * Behaves almost like this code:
 *
 * Additionally, interrupts all effects on any failure.
 *
 * @dataFirst forEachUnitPar_
 */
function forEachUnitPar(f, __trace) {
  return (as) => forEachUnitPar_(as, f, __trace)
}
exports.forEachUnitPar = forEachUnitPar
/**
 * Applies the function `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * For a sequential version of this method, see `forEach`.
 */
function forEachPar_(as, f, __trace) {
  return core.suspend(
    () =>
      core.chain_(
        core.succeedWith(() => []),
        (array) =>
          map.map_(
            forEachUnitPar_(
              I.map_(as, (a, n) => [a, n]),
              ([a, n]) =>
                core.chain_(
                  core.suspend(() => f(a)),
                  (b) =>
                    core.succeedWith(() => {
                      array[n] = b
                    })
                )
            ),
            () => Chunk.from(array)
          )
      ),
    __trace
  )
}
exports.forEachPar_ = forEachPar_
/**
 * Applies the function `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * For a sequential version of this method, see `forEach`.
 *
 * @dataFirst forEachPar_
 */
function forEachPar(f, __trace) {
  return (as) => forEachPar_(as, f, __trace)
}
exports.forEachPar = forEachPar
/**
 * Applies the function `f` to each element of the `Iterable[A]` and runs
 * produced effects in parallel, discarding the results.
 *
 * Unlike `forEachUnitPar_`, this method will use at most up to `n` fibers.
 */
function forEachUnitParN_(as, n, f, __trace) {
  const as_ = L.from(as)
  const size = L.size(as_)
  function worker(q, ref) {
    return whenM.whenM_(
      core.chain_(core.chain_(Q.take(q), f), () => worker(q, ref)),
      Ref.modify_(ref, (n) => Tp.tuple(n > 0, n - 1))
    )
  }
  return core.suspend(
    () =>
      bracket.bracket_(
        makeBoundedQueue(n),
        (q) =>
          tap.tap_(
            Do.bind_(
              tap.tap_(
                Do.bind_(Do.do, "ref", () => Ref.makeRef(size)),
                () => core.fork(forEachUnit_(as, (x) => Q.offer_(q, x)))
              ),
              "fibers",
              ({ ref }) =>
                collectAll(L.map_(L.range_(0, n), () => core.fork(worker(q, ref))))
            ),
            ({ fibers }) => forEach_(fibers, (_) => _.await)
          ),
        (q) => Q.shutdown(q)
      ),
    __trace
  )
}
exports.forEachUnitParN_ = forEachUnitParN_
/**
 * Applies the function `f` to each element of the `Iterable[A]` and runs
 * produced effects in parallel, discarding the results.
 *
 * Unlike `forEachUnitPar_`, this method will use at most up to `n` fibers.
 *
 * @dataFirst forEachUnitParN_
 */
function forEachUnitParN(n, f, __trace) {
  return (as) => forEachUnitParN_(as, n, f, __trace)
}
exports.forEachUnitParN = forEachUnitParN
/**
 * Applies the functionw `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * Unlike `forEachPar`, this method will use at most up to `n` fibers.
 */
function forEachParN_(as, n, f, __trace) {
  function worker(q, pairs, ref) {
    return whenM.whenM_(
      core.chain_(
        core.chain_(Q.take(q), ({ tuple: [p, a] }) =>
          core.foldCauseM_(
            core.suspend(() => f(a)),
            (c) => forEach_(pairs, (_) => promise.halt(c)(_.get(0))),
            (b) => promise.succeed(b)(p)
          )
        ),
        () => worker(q, pairs, ref)
      ),
      Ref.modify_(ref, (n) => Tp.tuple(n > 0, n - 1))
    )
  }
  return core.suspend(
    () =>
      bracket.bracket_(
        makeBoundedQueue(n),
        (q) =>
          core.chain_(
            tap.tap_(
              tap.tap_(
                Do.bind_(
                  Do.bind_(Do.do, "pairs", () =>
                    forEach_(as, (a) => map.map_(promise.make(), (p) => Tp.tuple(p, a)))
                  ),
                  "ref",
                  ({ pairs }) => Ref.makeRef(Chunk.size(pairs))
                ),
                ({ pairs }) => core.fork(forEach_(pairs, (pair) => Q.offer_(q, pair)))
              ),
              ({ pairs, ref }) =>
                collectAllUnit(
                  L.map(() => core.fork(worker(q, pairs, ref)))(L.range_(0, n))
                )
            ),
            ({ pairs }) => forEach_(pairs, (_) => promise.await(_.get(0)))
          ),
        Q.shutdown
      ),
    __trace
  )
}
exports.forEachParN_ = forEachParN_
/**
 * Applies the functionw `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * Unlike `forEachPar`, this method will use at most up to `n` fibers.
 *
 * @dataFirst forEachParN_
 */
function forEachParN(n, f, __trace) {
  return (as) => forEachParN_(as, n, f, __trace)
}
exports.forEachParN = forEachParN
/**
 * Applies the function `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * For a sequential version of this method, see `forEach`.
 */
function forEachExec_(as, es, f, __trace) {
  switch (es._tag) {
    case "Sequential": {
      return forEach_(as, f, __trace)
    }
    case "Parallel": {
      return forEachPar_(as, f, __trace)
    }
    case "ParallelN": {
      return forEachParN_(as, es.n, f, __trace)
    }
  }
}
exports.forEachExec_ = forEachExec_
/**
 * Applies the function `f` to each element of the `Iterable<A>` in parallel,
 * and returns the results in a new `readonly B[]`.
 *
 * For a sequential version of this method, see `forEach`.
 *
 * @dataFirst forEachExec_
 */
function forEachExec(es, f, __trace) {
  return (as) => forEachExec_(as, es, f, __trace)
}
exports.forEachExec = forEachExec
/**
 * Evaluate each effect in the structure from left to right, and collect the
 * results. For a parallel version, see `collectAllPar`.
 */
function collectAll(as, __trace) {
  return forEach_(as, Function_1.identity, __trace)
}
exports.collectAll = collectAll
/**
 * Evaluate each effect in the structure in parallel, and collect the
 * results. For a sequential version, see `collectAll`.
 */
function collectAllPar(as, __trace) {
  return forEachPar_(as, Function_1.identity, __trace)
}
exports.collectAllPar = collectAllPar
/**
 * Evaluate each effect in the structure in parallel, and collect the
 * results. For a sequential version, see `collectAll`.
 *
 * Unlike `collectAllPar`, this method will use at most `n` fibers.
 *
 * @dataFirst collectAllParN_
 */
function collectAllParN(n, __trace) {
  return (as) => forEachParN_(as, n, Function_1.identity, __trace)
}
exports.collectAllParN = collectAllParN
/**
 * Evaluate each effect in the structure in parallel, and collect the
 * results. For a sequential version, see `collectAll`.
 *
 * Unlike `collectAllPar`, this method will use at most `n` fibers.
 */
function collectAllParN_(as, n, __trace) {
  return forEachParN_(as, n, Function_1.identity, __trace)
}
exports.collectAllParN_ = collectAllParN_
/**
 * Evaluate each effect in the structure from left to right, and discard the
 * results. For a parallel version, see `collectAllUnitPar`.
 */
function collectAllUnit(as, __trace) {
  return forEachUnit_(as, Function_1.identity, __trace)
}
exports.collectAllUnit = collectAllUnit
/**
 * Evaluate each effect in the structure in parallel, and discard the
 * results. For a sequential version, see `collectAllUnit`.
 */
function collectAllUnitPar(as, __trace) {
  return forEachUnitPar_(as, Function_1.identity, __trace)
}
exports.collectAllUnitPar = collectAllUnitPar
/**
 * Evaluate each effect in the structure in parallel, and discard the
 * results. For a sequential version, see `collectAllUnit`.
 *
 * Unlike `collectAllUnitPar`, this method will use at most `n` fibers.
 *
 * @dataFirst collectAllUnitParN_
 */
function collectAllUnitParN(n, __trace) {
  return (as) => forEachUnitParN_(as, n, Function_1.identity, __trace)
}
exports.collectAllUnitParN = collectAllUnitParN
/**
 * Evaluate each effect in the structure in parallel, and discard the
 * results. For a sequential version, see `collectAllUnit`.
 *
 * Unlike `collectAllUnitPar`, this method will use at most `n` fibers.
 */
function collectAllUnitParN_(as, n, __trace) {
  return forEachUnitParN_(as, n, Function_1.identity, __trace)
}
exports.collectAllUnitParN_ = collectAllUnitParN_
/**
 * Evaluate each effect in the structure with `collectAll`, and collect
 * the results with given partial function.
 */
function collectAllWith_(as, pf, __trace) {
  return map.map_(collectAll(as, __trace), ChunkFilterMap.filterMap(pf))
}
exports.collectAllWith_ = collectAllWith_
/**
 * Evaluate each effect in the structure with `collectAll`, and collect
 * the results with given partial function.
 *
 * @dataFirst collectAllWith_
 */
function collectAllWith(pf, __trace) {
  return (as) => collectAllWith_(as, pf, __trace)
}
exports.collectAllWith = collectAllWith
/**
 * Evaluate each effect in the structure with `collectAll`, and collect
 * the results with given partial function.
 */
function collectAllWithPar_(as, pf, __trace) {
  return map.map_(collectAllPar(as, __trace), ChunkFilterMap.filterMap(pf))
}
exports.collectAllWithPar_ = collectAllWithPar_
/**
 * Evaluate each effect in the structure with `collectAll`, and collect
 * the results with given partial function.
 *
 * @dataFirst collectAllWithPar_
 */
function collectAllWithPar(pf, __trace) {
  return (as) => collectAllWithPar_(as, pf, __trace)
}
exports.collectAllWithPar = collectAllWithPar
/**
 * Evaluate each effect in the structure with `collectAllPar`, and collect
 * the results with given partial function.
 *
 * Unlike `collectAllWithPar`, this method will use at most up to `n` fibers.
 */
function collectAllWithParN_(as, n, pf, __trace) {
  return map.map_(collectAllParN_(as, n, __trace), ChunkFilterMap.filterMap(pf))
}
exports.collectAllWithParN_ = collectAllWithParN_
/**
 * Evaluate each effect in the structure with `collectAllPar`, and collect
 * the results with given partial function.
 *
 * Unlike `collectAllWithPar`, this method will use at most up to `n` fibers.
 *
 * @dataFirst collectAllWithParN_
 */
function collectAllWithParN(n, pf, __trace) {
  return (as) => collectAllWithParN_(as, n, pf, __trace)
}
exports.collectAllWithParN = collectAllWithParN
/**
 * Evaluate and run each effect in the structure and collect discarding failed ones.
 */
function collectAllSuccesses(as, __trace) {
  return collectAllWith_(
    I.map_(as, (x) => core.result(x)),
    (e) => (e._tag === "Success" ? O.some(e.value) : O.none),
    __trace
  )
}
exports.collectAllSuccesses = collectAllSuccesses
/**
 * Evaluate and run each effect in the structure in parallel, and collect discarding failed ones.
 */
function collectAllSuccessesPar(as, __trace) {
  return collectAllWithPar_(
    I.map_(as, (x) => core.result(x)),
    (e) => (e._tag === "Success" ? O.some(e.value) : O.none),
    __trace
  )
}
exports.collectAllSuccessesPar = collectAllSuccessesPar
/**
 * Evaluate and run each effect in the structure in parallel, and collect discarding failed ones.
 *
 * Unlike `collectAllSuccessesPar`, this method will use at most up to `n` fibers.
 */
function collectAllSuccessesParN_(as, n, __trace) {
  return collectAllWithParN_(
    I.map_(as, (x) => core.result(x)),
    n,
    (e) => (e._tag === "Success" ? O.some(e.value) : O.none),
    __trace
  )
}
exports.collectAllSuccessesParN_ = collectAllSuccessesParN_
/**
 * Evaluate and run each effect in the structure in parallel, and collect discarding failed ones.
 *
 * Unlike `collectAllSuccessesPar`, this method will use at most up to `n` fibers.
 *
 * @dataFirst collectAllSuccessesParN_
 */
function collectAllSuccessesParN(n, __trace) {
  return (as) => collectAllSuccessesParN_(as, n, __trace)
}
exports.collectAllSuccessesParN = collectAllSuccessesParN
/**
 * Joins all fibers, awaiting their _successful_ completion.
 * Attempting to join a fiber that has erred will result in
 * a catchable error, _if_ that error does not result from interruption.
 */
function fiberJoinAll(as, __trace) {
  return tap.tap_(
    core.chain_(fiberWaitAll(as), done_1.done),
    () => forEach_(as, (f) => f.inheritRefs),
    __trace
  )
}
exports.fiberJoinAll = fiberJoinAll
/**
 * Awaits on all fibers to be completed, successfully or not.
 */
function fiberWaitAll(as, __trace) {
  return core.result(
    forEachPar_(as, (f) => core.chain_(f.await, done_1.done)),
    __trace
  )
}
exports.fiberWaitAll = fiberWaitAll
/**
 * Releases all the finalizers in the releaseMap according to the ExecutionStrategy
 */
function releaseMapReleaseAll(exit, execStrategy, __trace) {
  return (_) =>
    flatten.flatten(
      Ref.modify_(_.ref, (s) => {
        switch (s._tag) {
          case "Exited": {
            return Tp.tuple(core.unit, s)
          }
          case "Running": {
            switch (execStrategy._tag) {
              case "Sequential": {
                return Tp.tuple(
                  core.chain_(
                    forEach_(
                      Array.from(s.finalizers()).reverse(),
                      ([_, f]) => core.result(f(exit)),
                      __trace
                    ),
                    (e) =>
                      (0, done_1.done)(
                        O.getOrElse_(Ex.collectAll(...e), () => Ex.succeed([]))
                      )
                  ),
                  new Exited_1.Exited(s.nextKey, exit)
                )
              }
              case "Parallel": {
                return Tp.tuple(
                  core.chain_(
                    forEachPar_(
                      Array.from(s.finalizers()).reverse(),
                      ([_, f]) => core.result(f(exit)),
                      __trace
                    ),
                    (e) =>
                      (0, done_1.done)(
                        O.getOrElse_(Ex.collectAllPar(...e), () => Ex.succeed([]))
                      )
                  ),
                  new Exited_1.Exited(s.nextKey, exit)
                )
              }
              case "ParallelN": {
                return Tp.tuple(
                  core.chain_(
                    forEachParN_(
                      Array.from(s.finalizers()).reverse(),
                      execStrategy.n,
                      ([_, f]) => core.result(f(exit)),
                      __trace
                    ),
                    (e) =>
                      (0, done_1.done)(
                        O.getOrElse_(Ex.collectAllPar(...e), () => Ex.succeed([]))
                      )
                  ),
                  new Exited_1.Exited(s.nextKey, exit)
                )
              }
            }
          }
        }
      })
    )
}
exports.releaseMapReleaseAll = releaseMapReleaseAll
/**
 * Creates a `Managed` value that acquires the original resource in a fiber,
 * and provides that fiber. The finalizer for this value will interrupt the fiber
 * and run the original finalizer.
 */
function managedFork(self, __trace) {
  return new managed_1.Managed(
    interruption.uninterruptibleMask(({ restore }) =>
      map.map_(
        Do.bind_(
          Do.bind_(
            Do.bind_(
              Do.let_(
                Do.let_(
                  Do.bind_(Do.do, "tp", () => (0, environment_1.environment)()),
                  "r",
                  ({ tp }) => tp.get(0)
                ),
                "outerReleaseMap",
                ({ tp }) => tp.get(1)
              ),
              "innerReleaseMap",
              () => makeReleaseMap_1.makeReleaseMap
            ),
            "fiber",
            ({ innerReleaseMap, r }) =>
              restore(
                core.provideAll_(
                  coreScope.forkDaemon(map.map_(self.effect, (_) => _.get(1))),
                  Tp.tuple(r, innerReleaseMap),
                  __trace
                )
              )
          ),
          "releaseMapEntry",
          ({ fiber, innerReleaseMap, outerReleaseMap }) =>
            (0, add_1.add)((e) =>
              core.chain_(
                (0, interrupt_1.interrupt)(fiber),
                () =>
                  releaseMapReleaseAll(
                    e,
                    ExecutionStrategy_1.sequential
                  )(innerReleaseMap),
                __trace
              )
            )(outerReleaseMap)
        ),
        ({ fiber, releaseMapEntry }) => Tp.tuple(releaseMapEntry, fiber)
      )
    )
  )
}
exports.managedFork = managedFork
/**
 * Run an effect while acquiring the resource before and releasing it after
 */
function managedUse_(self, f, __trace) {
  return (0, bracketExit_1.bracketExit_)(
    makeReleaseMap_1.makeReleaseMap,
    (rm) =>
      core.chain_(
        (0, provideSome_1.provideSome_)(self.effect, (r) => Tp.tuple(r, rm)),
        (a) => f(a.get(1)),
        __trace
      ),
    (rm, ex) => releaseMapReleaseAll(ex, ExecutionStrategy_1.sequential, __trace)(rm)
  )
}
exports.managedUse_ = managedUse_
class BackPressureStrategy {
  constructor() {
    this.putters = new MutableQueue_1.Unbounded()
  }
  handleSurplus(as, queue, takers, isShutdown) {
    return core.descriptorWith((d) =>
      core.suspend(() => {
        const p = promise.unsafeMake(d.id)
        return interruption.onInterrupt_(
          core.suspend(() => {
            this.unsafeOffer(as, p)
            this.unsafeOnQueueEmptySpace(queue)
            Q.unsafeCompleteTakers(this, queue, takers)
            if (isShutdown.get) {
              return interruption.interrupt
            } else {
              return promise.await(p)
            }
          }),
          () => core.succeedWith(() => this.unsafeRemove(p))
        )
      })
    )
  }
  unsafeRemove(p) {
    Q.unsafeOfferAll(
      this.putters,
      ChunkFilter.filter_(Q.unsafePollAll(this.putters), ([_, __]) => __ !== p)
    )
  }
  unsafeOffer(as, p) {
    let bs = as
    while (Chunk.size(bs) > 0) {
      const head = Chunk.unsafeGet_(bs, 0)
      bs = Chunk.drop_(bs, 1)
      if (Chunk.size(bs) === 0) {
        this.putters.offer([head, p, true])
      } else {
        this.putters.offer([head, p, false])
      }
    }
  }
  unsafeOnQueueEmptySpace(queue) {
    let keepPolling = true
    while (keepPolling && !queue.isFull) {
      const putter = this.putters.poll(undefined)
      if (putter != null) {
        const offered = queue.offer(putter[0])
        if (offered && putter[2]) {
          Q.unsafeCompletePromise(putter[1], true)
        } else if (!offered) {
          Q.unsafeOfferAll(
            this.putters,
            Chunk.prepend_(Q.unsafePollAll(this.putters), putter)
          )
        }
      } else {
        keepPolling = false
      }
    }
  }
  get shutdown() {
    return asUnit.asUnit(
      tap.tap_(
        Do.bind_(
          Do.bind_(Do.do, "fiberId", () => fiberId.fiberId),
          "putters",
          () => core.succeedWith(() => Q.unsafePollAll(this.putters))
        ),
        (s) =>
          forEachPar_(s.putters, ([_, p, lastItem]) =>
            lastItem ? promise.interruptAs(s.fiberId)(p) : core.unit
          )
      )
    )
  }
  get surplusSize() {
    return this.putters.size
  }
}
exports.BackPressureStrategy = BackPressureStrategy
/**
 * Creates a bounded queue
 */
function makeBoundedQueue(capacity, __trace) {
  return core.chain_(
    core.succeedWith(() => new MutableQueue_1.Bounded(capacity)),
    (x) => createQueue_(x, new BackPressureStrategy()),
    __trace
  )
}
exports.makeBoundedQueue = makeBoundedQueue
/**
 * Unsafely creates a queue
 */
function unsafeCreateQueue(queue, takers, shutdownHook, shutdownFlag, strategy) {
  return new UnsafeCreate(queue, takers, shutdownHook, shutdownFlag, strategy)
}
exports.unsafeCreateQueue = unsafeCreateQueue
class UnsafeCreate extends xqueue_1.XQueueInternal {
  constructor(queue, takers, shutdownHook, shutdownFlag, strategy) {
    super()
    this.queue = queue
    this.takers = takers
    this.shutdownHook = shutdownHook
    this.shutdownFlag = shutdownFlag
    this.strategy = strategy
    this.awaitShutdown = promise.await(this.shutdownHook)
    this.capacity = this.queue.capacity
    this.isShutdown = core.succeedWith(() => this.shutdownFlag.get)
    this.shutdown = (0, deps_core_1.descriptorWith)((d) =>
      core.suspend(() => {
        this.shutdownFlag.set(true)
        return interruption.uninterruptible(
          whenM.whenM_(
            core.chain_(
              forEachPar_(Q.unsafePollAll(this.takers), promise.interruptAs(d.id)),
              () => this.strategy.shutdown
            ),
            promise.succeed(undefined)(this.shutdownHook)
          )
        )
      })
    )
    this.size = core.suspend(() => {
      if (this.shutdownFlag.get) {
        return interruption.interrupt
      } else {
        return core.succeed(
          this.queue.size - this.takers.size + this.strategy.surplusSize
        )
      }
    })
    this.take = (0, deps_core_1.descriptorWith)((d) =>
      core.suspend(() => {
        if (this.shutdownFlag.get) {
          return interruption.interrupt
        }
        const item = this.queue.poll(undefined)
        if (item != null) {
          this.strategy.unsafeOnQueueEmptySpace(this.queue)
          return core.succeed(item)
        } else {
          const p = promise.unsafeMake(d.id)
          return interruption.onInterrupt_(
            core.suspend(() => {
              this.takers.offer(p)
              Q.unsafeCompleteTakers(this.strategy, this.queue, this.takers)
              if (this.shutdownFlag.get) {
                return interruption.interrupt
              } else {
                return promise.await(p)
              }
            }),
            () => core.succeedWith(() => Q.unsafeRemove(this.takers, p))
          )
        }
      })
    )
    this.takeAll = core.suspend(() => {
      if (this.shutdownFlag.get) {
        return interruption.interrupt
      } else {
        return core.succeedWith(() => {
          const as = Q.unsafePollAll(this.queue)
          this.strategy.unsafeOnQueueEmptySpace(this.queue)
          return as
        })
      }
    })
  }
  offer(a) {
    return core.suspend(() => {
      if (this.shutdownFlag.get) {
        return interruption.interrupt
      } else {
        const taker = this.takers.poll(undefined)
        if (taker != null) {
          Q.unsafeCompletePromise(taker, a)
          return core.succeed(true)
        } else {
          const succeeded = this.queue.offer(a)
          if (succeeded) {
            return core.succeed(true)
          } else {
            return this.strategy.handleSurplus(
              Chunk.single(a),
              this.queue,
              this.takers,
              this.shutdownFlag
            )
          }
        }
      }
    })
  }
  offerAll(as) {
    const arr = Chunk.from(as)
    return core.suspend(() => {
      if (this.shutdownFlag.get) {
        return interruption.interrupt
      } else {
        const pTakers = this.queue.isEmpty
          ? Q.unsafePollN(this.takers, Chunk.size(arr))
          : Chunk.empty()
        const {
          tuple: [forTakers, remaining]
        } = ChunkSplitAt.splitAt_(arr, Chunk.size(pTakers))
        ChunkForEach.forEach_(
          ChunkZip.zip_(pTakers, forTakers),
          ({ tuple: [taker, item] }) => {
            Q.unsafeCompletePromise(taker, item)
          }
        )
        if (Chunk.size(remaining) === 0) {
          return core.succeed(true)
        }
        const surplus = Q.unsafeOfferAll(this.queue, remaining)
        Q.unsafeCompleteTakers(this.strategy, this.queue, this.takers)
        if (Chunk.size(surplus) === 0) {
          return core.succeed(true)
        } else {
          return this.strategy.handleSurplus(
            surplus,
            this.queue,
            this.takers,
            this.shutdownFlag
          )
        }
      }
    })
  }
  takeUpTo(n) {
    return core.suspend(() => {
      if (this.shutdownFlag.get) {
        return interruption.interrupt
      } else {
        return core.succeedWith(() => {
          const as = Q.unsafePollN(this.queue, n)
          this.strategy.unsafeOnQueueEmptySpace(this.queue)
          return as
        })
      }
    })
  }
}
/**
 * Creates a queue
 */
function createQueue_(queue, strategy, __trace) {
  return map.map_(
    promise.make(),
    (p) =>
      unsafeCreateQueue(
        queue,
        new MutableQueue_1.Unbounded(),
        p,
        new AtomicBoolean_1.AtomicBoolean(false),
        strategy
      ),
    __trace
  )
}
exports.createQueue_ = createQueue_
/**
 * Creates a queue
 *
 * @dataFirst createQueue_
 */
function createQueue(strategy, __trace) {
  return (queue) => createQueue_(queue, strategy, __trace)
}
exports.createQueue = createQueue
//# sourceMappingURL=excl-forEach.js.map
