"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.raceAllWait = exports.raceAll = exports.raceAllWithStrategy = void 0
// tracing: off
const Chunk = __importStar(require("../Collections/Immutable/Chunk"))
const Tp = __importStar(require("../Collections/Immutable/Tuple"))
const Exit = __importStar(require("../Exit"))
const Fiber = __importStar(require("../Fiber"))
const Function_1 = require("../Function")
const P = __importStar(require("../Promise"))
const Ref = __importStar(require("../Ref"))
const as = __importStar(require("./as"))
const asUnit = __importStar(require("./asUnit"))
const core = __importStar(require("./core"))
const Do = __importStar(require("./do"))
const excl_forEach_1 = require("./excl-forEach")
const flatten_1 = require("./flatten")
const interruption = __importStar(require("./interruption"))
const map = __importStar(require("./map"))
const tap = __importStar(require("./tap"))
function arbiter(fibers, winner, promise, fails) {
  return (res) =>
    Exit.foldM(
      (e) =>
        (0, flatten_1.flatten)(
          Ref.modify_(fails, (c) =>
            Tp.tuple(c === 0 ? asUnit.asUnit(P.halt(e)(promise)) : core.unit, c - 1)
          )
        ),
      (a) =>
        core.chain_(P.succeed(Tp.tuple(a, winner))(promise), (set) =>
          set
            ? Chunk.reduce_(fibers, core.unit, (io, f) =>
                f === winner ? io : tap.tap_(io, () => Fiber.interrupt(f))
              )
            : core.unit
        )
    )(res)
}
/**
 * Returns an effect that races this effect with all the specified effects,
 * yielding the value of the first effect to succeed with a value.
 * Losers of the race will be interrupted immediately.
 *
 * Note: in case of success eventual interruption errors are ignored
 */
function raceAllWithStrategy(ios, interruptStrategy, __trace) {
  return map.map_(
    tap.tap_(
      Do.bind_(
        Do.bind_(
          Do.bind_(Do.do, "done", () => P.make()),
          "fails",
          () => Ref.makeRef(ios.length)
        ),
        "c",
        ({ done, fails }) =>
          interruption.uninterruptibleMask(
            ({ restore }) =>
              map.map_(
                Do.bind_(
                  Do.let_(
                    tap.tap_(
                      Do.bind_(Do.do, "fs", () =>
                        (0, excl_forEach_1.forEach_)(ios, (x) =>
                          core.fork(interruption.interruptible(x))
                        )
                      ),
                      ({ fs }) =>
                        Chunk.reduce_(fs, core.unit, (io, f) =>
                          core.chain_(io, () =>
                            core.fork(core.chain_(f.await, arbiter(fs, f, done, fails)))
                          )
                        )
                    ),
                    "inheritRefs",
                    () => (res) => as.as_(res.get(1).inheritRefs, res.get(0))
                  ),
                  "c",
                  ({ fs, inheritRefs }) =>
                    interruption.onInterrupt_(
                      restore(core.chain_(P.await(done), inheritRefs)),
                      () =>
                        Chunk.reduce_(fs, core.unit, (io, f) =>
                          tap.tap_(io, () => Fiber.interrupt(f))
                        )
                    )
                ),
                ({ c, fs }) => ({ c, fs })
              ),
            __trace
          )
      ),
      ({ c: { fs } }) =>
        interruptStrategy === "wait"
          ? (0, excl_forEach_1.forEach_)(fs, (f) => f.await)
          : core.unit
    ),
    ({ c: { c } }) => c
  )
}
exports.raceAllWithStrategy = raceAllWithStrategy
/**
 * Returns an effect that races this effect with all the specified effects,
 * yielding the value of the first effect to succeed with a value.
 * Losers of the race will be interrupted immediately.
 *
 * Note: in case of success eventual interruption errors are ignored
 */
function raceAll(ios, __trace) {
  return raceAllWithStrategy(ios, "background", __trace)
}
exports.raceAll = raceAll
/**
 * Returns an effect that races this effect with all the specified effects,
 * yielding the value of the first effect to succeed with a value.
 * Losers of the race will be interrupted immediately.
 *
 * Note: in case of success eventual interruption errors are ignored
 */
function raceAllWait(ios, __trace) {
  return raceAllWithStrategy(ios, "wait", __trace)
}
exports.raceAllWait = raceAllWait
//# sourceMappingURL=raceAll.js.map
