"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.switchable = void 0
// tracing: off
const Tp = __importStar(require("../../Collections/Immutable/Tuple"))
const ExecutionStrategy_1 = require("../../Effect/ExecutionStrategy")
const Function_1 = require("../../Function")
const Option_1 = require("../../Option")
const core_1 = require("../core")
const T = __importStar(require("../deps"))
const Do = __importStar(require("../do"))
const addIfOpen = __importStar(require("../ReleaseMap/addIfOpen"))
const makeReleaseMap = __importStar(require("../ReleaseMap/makeReleaseMap"))
const releaseAll = __importStar(require("../ReleaseMap/releaseAll"))
const replace = __importStar(require("../ReleaseMap/replace"))
const releaseMap_1 = require("./releaseMap")
/**
 * Returns a `Managed` value that represents a managed resource that can
 * be safely swapped within the scope of the `Managed`. The function provided
 * inside the `Managed` can be used to switch the resource currently in use.
 *
 * When the resource is switched, the finalizer for the previous finalizer will
 * be executed uninterruptibly. If the effect executing inside the `use`
 * is interrupted, the finalizer for the resource currently in use is guaranteed
 * to execute.
 *
 * This constructor can be used to create an expressive control flow that uses
 * several instances of a managed resource.
 */
function switchable(__trace) {
  return (0, core_1.map)(
    ({ key, releaseMap }) =>
      (newResource) =>
        T.uninterruptibleMask(({ restore }) =>
          T.map_(
            T.tap_(
              T.bind_(
                T.bind_(
                  T.bind_(
                    T.zipRight_(
                      T.chain_(
                        replace.replace(key, (_) => T.unit)(releaseMap),
                        (0, Option_1.fold)(
                          () => T.unit,
                          (fin) => fin(T.exitUnit)
                        )
                      ),
                      T.do
                    ),
                    "r",
                    () => T.environment()
                  ),
                  "inner",
                  () => makeReleaseMap.makeReleaseMap
                ),
                "a",
                ({ inner, r }) =>
                  restore(T.provideAll_(newResource.effect, Tp.tuple(r, inner)))
              ),
              ({ inner }) =>
                replace.replace(key, (exit) =>
                  releaseAll.releaseAll(exit, ExecutionStrategy_1.sequential)(inner)
                )(releaseMap)
            ),
            ({ a }) => a.get(1)
          )
        ),
    __trace
  )(
    Do.bind_(
      Do.bind_(Do.do, "releaseMap", () => releaseMap_1.releaseMap),
      "key",
      ({ releaseMap }) =>
        T.toManaged(
          T.chain_(
            addIfOpen.addIfOpen((_) => T.unit)(releaseMap),
            (0, Option_1.fold)(() => T.interrupt, T.succeed)
          )
        )
    )
  )
}
exports.switchable = switchable
//# sourceMappingURL=switchable.js.map
