"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
  }
var __exportStar =
  (this && this.__exportStar) ||
  function (m, exports) {
    for (var p in m)
      if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p))
        __createBinding(exports, m, p)
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.retry =
  exports.orElse =
  exports.orDie =
  exports.mapError =
  exports.second =
  exports.first =
  exports.catchAll =
  exports.launch =
  exports.restrict =
  exports.bracketConstructorM =
  exports.bracketConstructor =
  exports.fromConstructorManaged =
  exports.fromConstructorM =
  exports.fromConstructor =
  exports.flatten =
  exports.chain_ =
  exports.chain =
  exports.map_ =
  exports.map =
  exports.fresh =
  exports.toRuntime =
  exports.main =
  exports.allSeq =
  exports.all =
  exports.andSeq_ =
  exports.andSeq =
  exports.zip =
  exports.zip_ =
  exports.fromFunction =
  exports.fromManaged =
  exports.fromEffect =
  exports.prepare =
  exports.pure =
  exports.zipPar =
  exports.zipPar_ =
  exports.zipWithPar =
  exports.succeed =
  exports.fail =
  exports.zipWithPar_ =
  exports.suspend =
    void 0
// tracing: off
const C = __importStar(require("../Cause"))
const CL = __importStar(require("../Clock"))
const Tp = __importStar(require("../Collections/Immutable/Tuple"))
const E = __importStar(require("../Either"))
const Function_1 = require("../Function")
const Has_1 = require("../Has")
const definitions_1 = require("./definitions")
const T = __importStar(require("./deps-effect"))
const M = __importStar(require("./deps-managed"))
__exportStar(require("./definitions"), exports)
function environmentFor(has, a) {
  return M.fromEffect(
    T.access((r) => ({
      [has.key]: (0, Has_1.mergeEnvironments)(has, r, a)[has.key]
    }))
  )
}
/**
 * Lazily constructs a layer. This is useful to avoid infinite recursion when
 * creating layers that refer to themselves.
 */
function suspend(f) {
  return new definitions_1.LayerSuspend(f)
}
exports.suspend = suspend
/**
 * Combines this layer with the specified layer, producing a new layer that
 * has the inputs of both layers, and the outputs of both layers combined
 * using the specified function.
 */
function zipWithPar_(self, that, f) {
  return new definitions_1.LayerZipWithPar(self, that, f)
}
exports.zipWithPar_ = zipWithPar_
/**
 * Constructs a layer that fails with the specified value.
 */
function fail(e) {
  return (0, definitions_1.fromRawManaged)(M.fail(e))
}
exports.fail = fail
/**
 * Constructs a layer from the specified value.
 */
function succeed(resource) {
  return (0, definitions_1.fromRawManaged)(M.succeed(resource))
}
exports.succeed = succeed
/**
 * Combines this layer with the specified layer, producing a new layer that
 * has the inputs of both layers, and the outputs of both layers combined
 * using the specified function.
 */
function zipWithPar(that, f) {
  return (self) => zipWithPar_(self, that, f)
}
exports.zipWithPar = zipWithPar
/**
 * Combines this layer with the specified layer, producing a new layer that
 * has the inputs of both layers, and the outputs of both layers combined
 * into a tuple.
 */
function zipPar_(self, that) {
  return zipWithPar_(self, that, Tp.tuple)
}
exports.zipPar_ = zipPar_
/**
 * Combines this layer with the specified layer, producing a new layer that
 * has the inputs of both layers, and the outputs of both layers combined
 * into a tuple.
 */
function zipPar(that) {
  return (self) => zipPar_(self, that)
}
exports.zipPar = zipPar
/**
 * Construct a service layer from a value
 */
function pure(has) {
  return (resource) =>
    new definitions_1.LayerManaged(
      M.chain_(M.fromEffect(T.succeed(resource)), (a) => environmentFor(has, a))
    ).setKey(has.key)
}
exports.pure = pure
/**
 * DSL to construct service layers with acquire->open->release
 */
function prepare(has) {
  return (acquire) => ({
    open: (open) => ({
      release: (release) =>
        fromManaged(has)(
          M.chain_(
            M.makeExit_(acquire, (a) => release(a)),
            (a) => M.fromEffect(T.map_(open(a), () => a))
          )
        )
    }),
    release: (release) => fromManaged(has)(M.makeExit_(acquire, (a) => release(a)))
  })
}
exports.prepare = prepare
/**
 * Constructs a layer from the specified effect.
 */
function fromEffect(has) {
  return (resource) =>
    new definitions_1.LayerManaged(
      M.chain_(M.fromEffect(resource), (a) => environmentFor(has, a))
    ).setKey(has.key)
}
exports.fromEffect = fromEffect
/**
 * Constructs a layer from a managed resource.
 */
function fromManaged(has) {
  return (resource) =>
    new definitions_1.LayerManaged(
      M.chain_(resource, (a) => environmentFor(has, a))
    ).setKey(has.key)
}
exports.fromManaged = fromManaged
/**
 * Constructs a layer from the environment using the specified function.
 */
function fromFunction(tag) {
  return (f) => fromEffect(tag)(T.access(f))
}
exports.fromFunction = fromFunction
/**
 * Zips layers together
 */
function zip_(self, that) {
  return new definitions_1.LayerZipWithSeq(self, that, Tp.tuple)
}
exports.zip_ = zip_
/**
 * Zips layers together
 */
function zip(right) {
  return (left) => zip_(left, right)
}
exports.zip = zip
/**
 * Merges layers sequentially
 */
function andSeq(that) {
  return (self) => andSeq_(self, that)
}
exports.andSeq = andSeq
/**
 * Merges layers sequentially
 */
function andSeq_(self, that) {
  return new definitions_1.LayerZipWithSeq(self, that, (l, r) => ({ ...l, ...r }))
}
exports.andSeq_ = andSeq_
/**
 * Merges all layers in parallel
 */
function all(...ls) {
  return new definitions_1.LayerAllPar(ls)
}
exports.all = all
/**
 * Merges all layers sequentially
 */
function allSeq(...ls) {
  return new definitions_1.LayerAllSeq(ls)
}
exports.allSeq = allSeq
/**
 * Type level bound to make sure a layer is complete
 */
function main(layer) {
  return layer
}
exports.main = main
/**
 * Converts a layer to a managed runtime
 */
function toRuntime(_) {
  return M.chain_((0, definitions_1.build)(_), (a) =>
    M.fromEffect(
      T.checkPlatform((platform) =>
        T.succeedWith(() => T.makeCustomRuntime(a, platform))
      )
    )
  )
}
exports.toRuntime = toRuntime
/**
 * Creates a fresh version of this layer that will not be shared.
 */
function fresh(layer) {
  return new definitions_1.LayerFresh(layer)
}
exports.fresh = fresh
/**
 * Returns a new layer whose output is mapped by the specified function.
 */
function map(f) {
  return (fa) => map_(fa, f)
}
exports.map = map
/**
 * Maps the output of the layer using f
 */
function map_(fa, f) {
  return new definitions_1.LayerMap(fa, f)
}
exports.map_ = map_
/**
 * Chains the output of the layer using f
 */
function chain(f) {
  return (fa) => chain_(fa, f)
}
exports.chain = chain
/**
 * Chains the output of the layer using f
 */
function chain_(fa, f) {
  return new definitions_1.LayerChain(fa, f)
}
exports.chain_ = chain_
/**
 * Flatten `Layer< R, E, Layer< R2, E2, A>>`
 */
function flatten(ffa) {
  return chain_(ffa, Function_1.identity)
}
exports.flatten = flatten
/**
 * Creates a layer from a constructor (...deps) => T
 */
function fromConstructor(tag) {
  return (f) =>
    (...tags) =>
      fromEffect(tag)(T.accessServicesT(...tags)((...services) => f(...services)))
}
exports.fromConstructor = fromConstructor
/**
 * Creates a layer from a constructor (...deps) => Effect<R, E, T>
 */
function fromConstructorM(tag) {
  return (f) =>
    (...tags) =>
      fromEffect(tag)(T.accessServicesTM(...tags)((...services) => f(...services)))
}
exports.fromConstructorM = fromConstructorM
/**
 * Creates a layer from a constructor (...deps) => Managed<R, E, T>
 */
function fromConstructorManaged(tag) {
  return (f) =>
    (...tags) =>
      fromManaged(tag)(
        M.chain_(
          M.fromEffect(T.accessServicesT(...tags)((...services) => f(...services))),
          Function_1.identity
        )
      )
}
exports.fromConstructorManaged = fromConstructorManaged
/**
 * Creates a layer from a constructor (...deps) => T
 * with an open + release operation
 */
function bracketConstructor(tag) {
  return (f) =>
    (...tags) =>
    (open, release) =>
      prepare(tag)(T.accessServicesT(...tags)((...services) => f(...services)))
        .open(open)
        .release(release)
}
exports.bracketConstructor = bracketConstructor
/**
 * Creates a layer from a constructor (...deps) => T
 * with an open + release operation
 */
function bracketConstructorM(tag) {
  return (f) =>
    (...tags) =>
    (open, release) =>
      prepare(tag)(T.accessServicesTM(...tags)((...services) => f(...services)))
        .open(open)
        .release(release)
}
exports.bracketConstructorM = bracketConstructorM
/**
 * Restrict output to only contain the specified services
 */
function restrict(...ts) {
  return (self) =>
    (0, definitions_1.compose_)(
      self,
      (0, definitions_1.fromRawEffect)(
        T.accessServicesT(...ts)((...servises) =>
          servises
            .map((s, i) => ({ [ts[i].key]: s }))
            .reduce((x, y) => ({ ...x, ...y }))
        )
      )
    )
}
exports.restrict = restrict
/**
 * Builds this layer and uses it until it is interrupted. This is useful when
 * your entire application is a layer, such as an HTTP server.
 */
function launch(self) {
  return M.useForever((0, definitions_1.build)(self))
}
exports.launch = launch
/**
 * Recovers from all errors.
 */
function catchAll(handler) {
  return (self) => {
    return (0, definitions_1.fold)(self)(
      (0, definitions_1.fromRawFunctionM)(({ tuple: [r, cause] }) =>
        E.fold_(
          C.failureOrCause(cause),
          (e) => T.succeed(Tp.tuple(r, e)),
          (c) => T.halt(c)
        )
      )[">=>"](handler)
    )((0, definitions_1.fromRawEffect)(T.environment()))
  }
}
exports.catchAll = catchAll
/**
 * A layer that passes along the first element of a tuple.
 */
function first() {
  return (0, definitions_1.fromRawFunction)((_) => _.get(0))
}
exports.first = first
/**
 * A layer that passes along the second element of a tuple.
 */
function second() {
  return (0, definitions_1.fromRawFunction)((_) => _.get(1))
}
exports.second = second
/**
 * Returns a layer with its error channel mapped using the specified
 * function.
 */
function mapError(f) {
  return catchAll((0, definitions_1.fromRawFunctionM)((_) => T.fail(f(_.get(1)))))
}
exports.mapError = mapError
/**
 * Translates effect failure into death of the fiber, making all failures
 * unchecked and not a part of the type of the layer.
 */
function orDie(self) {
  return catchAll((0, definitions_1.fromRawFunctionM)((_) => T.die(_.get(1))))(self)
}
exports.orDie = orDie
/**
 * Executes this layer and returns its output, if it succeeds, but otherwise
 * executes the specified layer.
 */
function orElse(that) {
  return catchAll(first()[">=>"](that))
}
exports.orElse = orElse
function retryLoop(self) {
  const update = (0, definitions_1.fromRawFunctionM)(
    ({
      tuple: [
        {
          tuple: [r, s]
        },
        e
      ]
    }) =>
      T.provideAll_(
        T.chain_(T.orDie(CL.currentTime), (now) =>
          T.chain_(s(now, e), (result) => {
            if (result._tag === "Done") {
              return T.fail(e)
            } else {
              return T.as_(
                CL.sleep(Math.abs(now - result.interval)),
                Tp.tuple(r, result.next)
              )
            }
          })
        ),
        r
      )
  )
  return catchAll(update[">=>"](suspend(() => fresh(retryLoop(self)))))(
    first()[">=>"](self)
  )
}
/**
 * Retries constructing this layer according to the specified schedule.
 */
function retry(self, schedule) {
  return zipPar_(
    (0, definitions_1.identity)(),
    (0, definitions_1.fromRawEffect)(T.succeed(schedule.step))
  )[">=>"](retryLoop(self))
}
exports.retry = retry
//# sourceMappingURL=core.js.map
