"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.await =
  exports.unit =
  exports.never =
  exports.toManaged =
  exports.interruptAs =
  exports.halt =
  exports.fail =
  exports.succeed =
  exports.done =
  exports.fold =
  exports.makeSynthetic =
  exports.collectAll =
  exports.zipLeft_ =
  exports.zipRight_ =
  exports.zip_ =
  exports.zipWith_ =
  exports.asUnit =
  exports.as =
  exports.orElseEither =
  exports.orElse =
  exports.mapFiber_ =
  exports.mapFiber =
  exports.map_ =
  exports.waitAll =
  exports.joinAll =
  exports.map =
  exports.mapM =
  exports.interruptFork =
  exports.interruptAll =
  exports.interruptAllAs =
  exports.fromEffect =
    void 0
// tracing: off
const Cause = __importStar(require("../Cause/core"))
const Chunk = __importStar(require("../Collections/Immutable/Chunk"))
const E = __importStar(require("../Either"))
const Exit = __importStar(require("../Exit/api"))
const Function_1 = require("../Function")
const IT = __importStar(require("../Iterable"))
const core_1 = require("../Managed/core")
const O = __importStar(require("../Option"))
const T = __importStar(require("./_internal/effect-api"))
const Fiber = __importStar(require("./core"))
const interrupt_1 = require("./interrupt")
/**
 * Lifts an IO into a `Fiber`.
 */
function fromEffect(effect) {
  return T.map_(T.result(effect), done)
}
exports.fromEffect = fromEffect
/**
 * Interrupts all fibers as by the specified fiber, awaiting their interruption.
 */
function interruptAllAs(id) {
  return (fs) =>
    IT.reduce_(fs, T.unit, (io, f) => T.asUnit(T.chain_(io, () => f.interruptAs(id))))
}
exports.interruptAllAs = interruptAllAs
/**
 * Interrupts all fibers, awaiting their interruption.
 */
function interruptAll(fs) {
  return T.chain_(T.fiberId, (id) => interruptAllAs(id)(fs))
}
exports.interruptAll = interruptAll
/**
 * Interrupts the fiber from whichever fiber is calling this method. The
 * interruption will happen in a separate daemon fiber, and the returned
 * effect will always resume immediately without waiting.
 */
function interruptFork(fiber) {
  return T.asUnit(T.forkDaemon((0, interrupt_1.interrupt)(fiber)))
}
exports.interruptFork = interruptFork
/**
 * Effectually maps over the value the fiber computes.
 */
function mapM(f) {
  return (fiber) => ({
    await: T.chain_(fiber.await, Exit.forEach(f)),
    getRef: (ref) => fiber.getRef(ref),
    inheritRefs: fiber.inheritRefs,
    interruptAs: (id) => T.chain_(fiber.interruptAs(id), Exit.forEach(f)),
    poll: T.chain_(
      fiber.poll,
      O.fold(
        () => T.succeed(O.none),
        (a) => T.map_(Exit.forEach_(a, f), O.some)
      )
    )
  })
}
exports.mapM = mapM
/**
 * Maps over the value the fiber computes.
 */
function map(f) {
  return mapM((a) => T.succeed(f(a)))
}
exports.map = map
/**
 * 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 joinAll(as) {
  return T.tap_(T.chain_(waitAll(as), T.done), () =>
    T.forEach_(as, (f) => f.inheritRefs)
  )
}
exports.joinAll = joinAll
/**
 * Awaits on all fibers to be completed, successfully or not.
 */
function waitAll(as) {
  return T.result(T.forEachPar_(as, (f) => T.chain_(f.await, T.done)))
}
exports.waitAll = waitAll
/**
 * Maps over the value the fiber computes.
 */
function map_(fiber, f) {
  return map(f)(fiber)
}
exports.map_ = map_
/**
 * Passes the success of this fiber to the specified callback, and continues
 * with the fiber that it returns.
 */
function mapFiber(f) {
  return (fiber) =>
    T.map_(fiber.await, (e) => {
      switch (e._tag) {
        case "Success": {
          return f(e.value)
        }
        case "Failure": {
          return halt(e.cause)
        }
      }
    })
}
exports.mapFiber = mapFiber
/**
 * Passes the success of this fiber to the specified callback, and continues
 * with the fiber that it returns.
 */
function mapFiber_(fiber, f) {
  return T.map_(fiber.await, (e) => {
    switch (e._tag) {
      case "Success": {
        return f(e.value)
      }
      case "Failure": {
        return halt(e.cause)
      }
    }
  })
}
exports.mapFiber_ = mapFiber_
/**
 * Returns a fiber that prefers `this` fiber, but falls back to the
 * `that` one when `this` one fails. Interrupting the returned fiber
 * will interrupt both fibers, sequentially, from left to right.
 */
function orElse(that) {
  return (fiber) => ({
    await: T.zipWith_(fiber.await, that.await, (a, b) =>
      a._tag === "Success" ? a : b
    ),
    getRef: (ref) =>
      T.zipWith_(fiber.getRef(ref), that.getRef(ref), (a, b) =>
        a === ref.initial ? b : a
      ),
    inheritRefs: T.chain_(fiber.inheritRefs, () => that.inheritRefs),
    interruptAs: (id) => T.chain_(fiber.interruptAs(id), () => that.interruptAs(id)),
    poll: T.zipWith_(fiber.poll, that.poll, (a, b) => {
      switch (a._tag) {
        case "Some": {
          return a.value._tag === "Success" ? a : b
        }
        case "None": {
          return O.none
        }
      }
    })
  })
}
exports.orElse = orElse
/**
 * Returns a fiber that prefers `this` fiber, but falls back to the
 * `that` one when `this` one fails. Interrupting the returned fiber
 * will interrupt both fibers, sequentially, from left to right.
 */
function orElseEither(that) {
  return (fiber) => orElse(map_(that, E.right))(map_(fiber, E.left))
}
exports.orElseEither = orElseEither
/**
 * Maps the output of this fiber to the specified constant.
 */
function as(b) {
  return (fiber) => map_(fiber, () => b)
}
exports.as = as
/**
 * Maps the output of this fiber to `void`.
 */
function asUnit(fiber) {
  return map_(fiber, () => undefined)
}
exports.asUnit = asUnit
/**
 * Zips this fiber with the specified fiber, combining their results using
 * the specified combiner function. Both joins and interruptions are performed
 * in sequential order from left to right.
 */
function zipWith_(fiberA, fiberB, f) {
  return {
    getRef: (ref) =>
      T.zipWith_(fiberA.getRef(ref), fiberB.getRef(ref), (a, b) => ref.join(a, b)),
    inheritRefs: T.chain_(fiberA.inheritRefs, () => fiberB.inheritRefs),
    interruptAs: (id) =>
      T.zipWith_(fiberA.interruptAs(id), fiberB.interruptAs(id), (ea, eb) =>
        Exit.zipWith_(ea, eb, f, Cause.both)
      ),
    poll: T.zipWith_(fiberA.poll, fiberB.poll, (oa, ob) =>
      O.chain_(oa, (ea) => O.map_(ob, (eb) => Exit.zipWith_(ea, eb, f, Cause.both)))
    ),
    await: T.result(
      T.zipWithPar_(T.chain_(fiberA.await, T.done), T.chain_(fiberB.await, T.done), f)
    )
  }
}
exports.zipWith_ = zipWith_
/**
 * Zips this fiber and the specified fiber together, producing a tuple of their output.
 */
function zip_(fiberA, fiberB) {
  return zipWith_(fiberA, fiberB, (a, b) => [a, b])
}
exports.zip_ = zip_
/**
 * Same as `zip` but discards the output of the left hand side.
 */
function zipRight_(fiberA, fiberB) {
  return zipWith_(fiberA, fiberB, (_, b) => b)
}
exports.zipRight_ = zipRight_
/**
 * Same as `zip` but discards the output of the right hand side.
 */
function zipLeft_(fiberA, fiberB) {
  return zipWith_(fiberA, fiberB, (a, _) => a)
}
exports.zipLeft_ = zipLeft_
/**
 * Collects all fibers into a single fiber producing an in-order list of the
 * results.
 */
function collectAll(fibers) {
  return {
    getRef: (ref) =>
      T.reduce_(fibers, ref.initial, (a, fiber) =>
        T.map_(fiber.getRef(ref), (a2) => ref.join(a, a2))
      ),
    inheritRefs: T.forEachUnit_(fibers, (f) => f.inheritRefs),
    interruptAs: (fiberId) =>
      T.map_(
        T.forEach_(fibers, (f) => f.interruptAs(fiberId)),
        Chunk.reduceRight(Exit.succeed(Chunk.empty()), (a, b) =>
          Exit.zipWith_(a, b, (_a, _b) => Chunk.prepend_(_b, _a), Cause.both)
        )
      ),
    poll: T.map_(
      T.forEach_(fibers, (f) => f.poll),
      Chunk.reduceRight(O.some(Exit.succeed(Chunk.empty())), (a, b) =>
        O.fold_(
          a,
          () => O.none,
          (ra) =>
            O.fold_(
              b,
              () => O.none,
              (rb) =>
                O.some(
                  Exit.zipWith_(ra, rb, (_a, _b) => Chunk.prepend_(_b, _a), Cause.both)
                )
            )
        )
      )
    ),
    await: waitAll(fibers)
  }
}
exports.collectAll = collectAll
/**
 * @optimize identity
 */
function makeSynthetic(_) {
  return new Fiber.Synthetic(_.await, _.getRef, _.inheritRefs, _.interruptAs, _.poll)
}
exports.makeSynthetic = makeSynthetic
/**
 * Folds over the runtime or synthetic fiber.
 */
function fold(runtime, syntetic) {
  return (fiber) => {
    switch (fiber._tag) {
      case "RuntimeFiber": {
        return runtime(fiber)
      }
      case "SyntheticFiber": {
        return syntetic(fiber)
      }
    }
  }
}
exports.fold = fold
/**
 * A fiber that is done with the specified `Exit` value.
 */
function done(exit) {
  return {
    await: T.succeed(exit),
    getRef: (ref) => T.succeed(ref.initial),
    inheritRefs: T.unit,
    interruptAs: () => T.succeed(exit),
    poll: T.succeed(O.some(exit))
  }
}
exports.done = done
/**
 * Returns a fiber that has already succeeded with the specified value.
 */
function succeed(a) {
  return done(Exit.succeed(a))
}
exports.succeed = succeed
/**
 * A fiber that has already failed with the specified value.
 */
function fail(e) {
  return done(Exit.fail(e))
}
exports.fail = fail
/**
 * Creates a `Fiber` that is halted with the specified cause.
 */
function halt(cause) {
  return done(Exit.halt(cause))
}
exports.halt = halt
/**
 * A fiber that is already interrupted.
 */
function interruptAs(id) {
  return done(Exit.interrupt(id))
}
exports.interruptAs = interruptAs
function toManaged(fiber) {
  return (0, core_1.make)(interrupt_1.interrupt)(T.succeed(fiber))
}
exports.toManaged = toManaged
/**
 * A fiber that never fails or succeeds.
 */
exports.never = {
  await: T.never,
  getRef: (fiberRef) => T.succeed(fiberRef.initial),
  interruptAs: (0, Function_1.constant)(T.never),
  inheritRefs: T.unit,
  poll: T.succeed(O.none)
}
/**
 * A fiber that has already succeeded with unit.
 */
exports.unit = succeed(undefined)
/**
 * Awaits the fiber, which suspends the awaiting fiber until the result of the fiber has been determined.
 */
function wait(fiber) {
  return fiber.await
}
exports.await = wait
//# sourceMappingURL=api.js.map
