"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.retry =
  exports.retry_ =
  exports.retryOrElse =
  exports.retryOrElse_ =
  exports.retryOrElseEither =
  exports.retryOrElseEither_ =
    void 0
const E = __importStar(require("../Either"))
const Function_1 = require("../Function")
const schedule = __importStar(require("../Schedule"))
const catchAll = __importStar(require("./catchAll"))
const core = __importStar(require("./core"))
const fail = __importStar(require("./fail"))
const foldM = __importStar(require("./foldM"))
const map = __importStar(require("./map"))
const orDie = __importStar(require("./orDie"))
function loop(self, orElse, driver) {
  return catchAll.catchAll_(
    map.map_(self, (a) => E.right(a)),
    (e) =>
      foldM.foldM_(
        driver.next(e),
        () =>
          core.chain_(orDie.orDie(driver.last), (o) =>
            map.map_(orElse(e, o), (a) => E.left(a))
          ),
        () => loop(self, orElse, driver)
      )
  )
}
/**
 * Returns an effect that retries this effect with the specified schedule when it fails, until
 * the schedule is done, then both the value produced by the schedule together with the last
 * error are passed to the specified recovery function.
 */
function retryOrElseEither_(self, policy, orElse, __trace) {
  return core.chain_(schedule.driver(policy), (a) => loop(self, orElse, a), __trace)
}
exports.retryOrElseEither_ = retryOrElseEither_
/**
 * Returns an effect that retries this effect with the specified schedule when it fails, until
 * the schedule is done, then both the value produced by the schedule together with the last
 * error are passed to the specified recovery function.
 *
 * @dataFirst retryOrElseEither_
 */
function retryOrElseEither(policy, orElse, __trace) {
  return (self) => retryOrElseEither_(self, policy, orElse, __trace)
}
exports.retryOrElseEither = retryOrElseEither
/**
 * Retries with the specified schedule, until it fails, and then both the
 * value produced by the schedule together with the last error are passed to
 * the recovery function.
 */
function retryOrElse_(self, policy, orElse, __trace) {
  return map.map_(
    retryOrElseEither_(self, policy, orElse, __trace),
    E.fold(Function_1.identity, Function_1.identity)
  )
}
exports.retryOrElse_ = retryOrElse_
/**
 * Retries with the specified schedule, until it fails, and then both the
 * value produced by the schedule together with the last error are passed to
 * the recovery function.
 *
 * @dataFirst retryOrElse_
 */
function retryOrElse(policy, orElse, __trace) {
  return (self) => retryOrElse_(self, policy, orElse, __trace)
}
exports.retryOrElse = retryOrElse
/**
 * Retries with the specified retry policy.
 * Retries are done following the failure of the original `io` (up to a fixed maximum with
 * `once` or `recurs` for example), so that that `io.retry(Schedule.once)` means
 * "execute `io` and in case of failure, try again once".
 */
function retry_(self, policy, __trace) {
  return retryOrElse_(self, policy, (e, _) => fail.fail(e), __trace)
}
exports.retry_ = retry_
/**
 * Retries with the specified retry policy.
 * Retries are done following the failure of the original `io` (up to a fixed maximum with
 * `once` or `recurs` for example), so that that `io.retry(Schedule.once)` means
 * "execute `io` and in case of failure, try again once".
 *
 * @dataFirst retry_
 */
function retry(policy, __trace) {
  return (self) => retry_(self, policy, __trace)
}
exports.retry = retry
//# sourceMappingURL=retry.js.map
