const fileName_1 = "(@effect/core) _src/io/Layer/memoMap.ts";
import * as tsplus_module_1 from "@tsplus/stdlib/data/Maybe/fromNullable";
import * as tsplus_module_2 from "@effect/core/io/Effect/operations/unit";
import * as tsplus_module_3 from "@effect/core/io/Scope/operations/addFinalizerExit";
import * as tsplus_module_4 from "@effect/core/io/Exit/operations/fold";
import * as tsplus_module_5 from "@effect/core/io/Effect/operations/onExit";
import * as tsplus_module_6 from "@tsplus/stdlib/data/Tuple/make";
import * as tsplus_module_7 from "@effect/core/io/Effect/operations/succeed";
import * as tsplus_module_8 from "@effect/core/io/Effect/operations/flatMap";
import * as tsplus_module_9 from "@effect/core/io/Scope/operations/close";
import * as tsplus_module_10 from "@effect/core/io/Effect/operations/zipRight";
import * as tsplus_module_11 from "@effect/core/io/Effect/operations/failCause";
import * as tsplus_module_12 from "@effect/core/io/Effect/operations/whenEffect";
import * as tsplus_module_13 from "@effect/core/io/Effect/operations/as";
import * as tsplus_module_14 from "@effect/core/io/Effect/operations/exit";
import * as tsplus_module_15 from "@effect/core/io/Scope/operations/make";
import * as tsplus_module_16 from "@effect/core/io/Effect/operations/do";
import * as tsplus_module_17 from "@effect/core/io/Effect/operations/interruption";
import * as tsplus_module_18 from "@effect/core/io/Ref/operations/make";
import * as tsplus_module_19 from "@effect/core/io/Deferred/operations/make";
import * as tsplus_module_20 from "@effect/core/io/Effect/operations/map";
import * as tsplus_module_21 from "@effect/core/io/Effect/operations/flatten";
import * as tsplus_module_22 from "@effect/core/io/Scope/definition";
import * as tsplus_module_23 from "@effect/core/io/Effect/operations/serviceWithEffect";
import * as tsplus_module_24 from "@effect/core/io/Effect/operations/scopeWith";
import * as tsplus_module_25 from "@effect/core/io/Effect/operations/foldCauseEffect";
import * as tsplus_module_26 from "@effect/core/io/Scope/operations/extend";
import * as tsplus_module_27 from "@effect/core/io/Effect/operations/provideEnvironment";
import * as tsplus_module_28 from "@effect/core/io/Effect/operations/zipWithPar";
import * as tsplus_module_29 from "@tsplus/stdlib/data/Match";
export const buildWithScope = buildWithScope_1;
export const withScope = withScope_1;
export const isFresh = isFresh_1;
import { instruction } from "@effect/core/io/Layer/definition";
/**
 * A `MemoMap` memoizes layers.
 */

export class MemoMap {
  constructor(ref) {
    this.ref = ref;
  }
  /**
   * Checks the memo map to see if a layer exists. If it is, immediately
   * returns it. Otherwise, obtains the layer, stores it in the memo map,
   * and adds a finalizer to the `Scope`.
   */


  getOrElseMemoize(layer, scope) {
    return tsplus_module_8.flatMap_(tsplus_module_7.succeed(scope, fileName_1 + ":22:26"), scope => tsplus_module_21.flattenNow(this.ref.modifyEffect(map => {
      const inMap = tsplus_module_1.fromNullable(map.get(layer));

      switch (inMap._tag) {
        case "Some":
          {
            const {
              tuple: [acquire, release]
            } = inMap.value;
            const cached = tsplus_module_5.onExit_(acquire, exit => tsplus_module_4.fold_(exit, () => tsplus_module_2.unit, () => tsplus_module_3.addFinalizerExit_(scope, release)), fileName_1 + ":32:71");
            return tsplus_module_7.succeed(() => tsplus_module_6.make(cached, map), fileName_1 + ":39:34");
          }

        case "None":
          {
            return tsplus_module_20.map_(tsplus_module_16.bindValue_(tsplus_module_16.bindValue_(tsplus_module_16.bind_(tsplus_module_16.bind_(tsplus_module_16.bind_(tsplus_module_16.Do(), "observers", () => tsplus_module_18.makeSynchronized(() => 0, fileName_1 + ":43:61"), fileName_1 + ":43:20"), "deferred", () => tsplus_module_19.make(fileName_1 + ":44:52"), fileName_1 + ":44:20"), "finalizerRef", () => tsplus_module_18.makeSynchronized(() => () => tsplus_module_2.unit, fileName_1 + ":45:64"), fileName_1 + ":45:20"), "resource", ({
              deferred,
              finalizerRef,
              observers
            }) => tsplus_module_17.uninterruptibleMask(({
              restore
            }) => tsplus_module_8.flatMap_(tsplus_module_16.bind_(tsplus_module_16.bindValue_(tsplus_module_16.Do(), "outerScope", () => scope, fileName_1 + ":49:31"), "innerScope", () => tsplus_module_15.make, fileName_1 + ":51:26"), ({
              innerScope,
              outerScope
            }) => tsplus_module_8.flatMap_(tsplus_module_14.exit(restore(() => tsplus_module_8.flatMap_(withScope_1(layer, () => innerScope, fileName_1 + ":53:46"), f => f(this), fileName_1 + ":53:66"), fileName_1 + ":53:30"), fileName_1 + ":54:30"), exit => {
              switch (exit._tag) {
                case "Failure":
                  {
                    return tsplus_module_10.zipRight_(tsplus_module_10.zipRight_(deferred.failCause(() => exit.cause, fileName_1 + ":59:51"), () => tsplus_module_9.close_(innerScope, () => exit), fileName_1 + ":59:65"), () => tsplus_module_11.failCause(() => exit.cause, fileName_1 + ":61:51"), fileName_1 + ":60:59");
                  }

                case "Success":
                  {
                    return tsplus_module_13.as_(tsplus_module_10.zipRight_(tsplus_module_10.zipRight_(tsplus_module_10.zipRight_(finalizerRef.set(exit => tsplus_module_12.whenEffect(() => observers.modify(n => tsplus_module_6.make(n === 1, n - 1), fileName_1 + ":67:51"), () => tsplus_module_9.close_(innerScope, () => exit), fileName_1 + ":66:50"), fileName_1 + ":65:54"), () => observers.update(n => n + 1, fileName_1 + ":71:59"), fileName_1 + ":71:42"), () => tsplus_module_3.addFinalizerExit_(outerScope, e => tsplus_module_8.flatMap_(finalizerRef.get(fileName_1 + ":73:86"), fin => fin(e), fileName_1 + ":73:96")), fileName_1 + ":72:42"), () => deferred.succeed(() => exit.value, fileName_1 + ":75:59"), fileName_1 + ":75:42"), () => exit.value, fileName_1 + ":76:36");
                  }
              }
            }, fileName_1 + ":55:33"), fileName_1 + ":52:29"), fileName_1 + ":47:43"), fileName_1 + ":46:25"), "memoized", ({
              deferred,
              finalizerRef,
              observers
            }) => tsplus_module_6.make(tsplus_module_5.onExit_(deferred.await(fileName_1 + ":84:33"), exit => tsplus_module_4.fold_(exit, () => tsplus_module_2.unit, () => observers.update(n => n + 1, fileName_1 + ":89:47")), fileName_1 + ":85:28"), e => tsplus_module_8.flatMap_(finalizerRef.get(fileName_1 + ":92:66"), fin => fin(e), fileName_1 + ":92:76")), fileName_1 + ":82:25"), ({
              memoized,
              resource
            }) => tsplus_module_6.make(resource, isFresh_1(layer) ? map : map.set(layer, memoized)), fileName_1 + ":94:19");
          }
      }
    }, fileName_1 + ":23:28"), fileName_1 + ":97:17"), fileName_1 + ":22:41");
  }

}
/**
 * Creates an empty `MemoMap`.
 */

export function makeMemoMap() {
  return tsplus_module_8.flatMap_(tsplus_module_18.makeSynchronized(() => new Map(), fileName_1 + ":106:31"), r => tsplus_module_7.succeed(() => new MemoMap(r), fileName_1 + ":108:45"), fileName_1 + ":108:23");
}
/**
 * Builds a layer into a scoped value.
 *
 * @tsplus fluent ets/Layer build
 */

export function build(self, __tsplusTrace) {
  return tsplus_module_23.serviceWithEffect(tsplus_module_22.Scope.Tag, scope => buildWithScope_1(self, () => scope, __tsplusTrace), __tsplusTrace);
}
/**
 * Builds a layer into an Effect value. Any resources associated with this layer
 * will be released when the specified scope is closed unless their scope has
 * been extended. This allows building layers where the lifetime of some of
 * the services output by the layer exceed the lifetime of the effect the
 * layer is provided to.
 *
 * @tsplus fluent ets/Layer buildWithScope
 */

function buildWithScope_1(self, scope, __tsplusTrace) {
  return tsplus_module_8.flatMap_(tsplus_module_16.bind_(tsplus_module_16.bind_(tsplus_module_16.Do(), "memoMap", () => makeMemoMap(), __tsplusTrace), "run", () => withScope_1(self, scope, __tsplusTrace), __tsplusTrace), ({
    memoMap,
    run
  }) => run(memoMap), __tsplusTrace);
}
/**
 * @tsplus fluent ets/Layer withScope
 */


function withScope_1(self, scope, __tsplusTrace) {
  return tsplus_module_29.matchTag_(self, {
    LayerApply: _ => tsplus_module_7.succeed(() => memoMap => _.self, __tsplusTrace),
    LayerExtendScope: _ => tsplus_module_7.succeed(() => memoMap => tsplus_module_24.scopeWith(scope => memoMap.getOrElseMemoize(_.self, () => scope), __tsplusTrace), __tsplusTrace),
    LayerFold: _ => tsplus_module_7.succeed(() => memoMap => tsplus_module_25.foldCauseEffect_(memoMap.getOrElseMemoize(_.self, scope), e => memoMap.getOrElseMemoize(_.failure(e), scope), r => memoMap.getOrElseMemoize(_.success(r), scope), __tsplusTrace), __tsplusTrace),
    LayerFresh: _ => tsplus_module_7.succeed(() => __ => buildWithScope_1(_.self, scope, __tsplusTrace), __tsplusTrace),
    LayerScoped: _ => tsplus_module_7.succeed(() => __ => tsplus_module_26.extend_(scope(), () => _.self), __tsplusTrace),
    LayerSuspend: _ => tsplus_module_7.succeed(() => memoMap => memoMap.getOrElseMemoize(_.self(), scope), __tsplusTrace),
    LayerTo: _ => tsplus_module_7.succeed(() => memoMap => tsplus_module_8.flatMap_(memoMap.getOrElseMemoize(_.self, scope), r => tsplus_module_27.provideEnvironment_(memoMap.getOrElseMemoize(_.that, scope), () => r, __tsplusTrace), __tsplusTrace), __tsplusTrace),
    LayerZipWithPar: _ => tsplus_module_7.succeed(() => memoMap => tsplus_module_28.zipWithPar_(memoMap.getOrElseMemoize(_.self, scope), () => memoMap.getOrElseMemoize(_.that, scope), _.f, __tsplusTrace), __tsplusTrace)
  });
}
/**
 * Returns whether this layer is a fresh version that will not be shared.
 *
 * @tsplus getter ets/Layer isFresh
 */


function isFresh_1(self) {
  return self._tag === "LayerFresh";
}
//# sourceMappingURL=memoMap.mjs.map