"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.set_ =
  exports.set =
  exports.get =
  exports.foldAll_ =
  exports.foldAll =
  exports.fold_ =
  exports.fold =
  exports.updateSomeAndGet_ =
  exports.updateSomeAndGet =
  exports.updateSome_ =
  exports.updateSome =
  exports.updateAndGet_ =
  exports.updateAndGet =
  exports.update_ =
  exports.update =
  exports.getAndUpdateSome_ =
  exports.getAndUpdateSome =
  exports.getAndUpdate_ =
  exports.getAndUpdate =
  exports.getAndSet_ =
  exports.getAndSet =
  exports.modifySome_ =
  exports.modifySome =
  exports.modify_ =
  exports.modify =
  exports.writeOnly =
  exports.readOnly =
  exports.mapEither_ =
  exports.mapEither =
  exports.map_ =
  exports.map =
  exports.filterOutput_ =
  exports.filterOutput =
  exports.filterInput_ =
  exports.filterInput =
  exports.dimapError_ =
  exports.dimapError =
  exports.dimapEither_ =
  exports.dimapEither =
  exports.dimap_ =
  exports.dimap =
  exports.contramapEither_ =
  exports.contramapEither =
  exports.contramap_ =
  exports.contramap =
  exports.collect_ =
  exports.collect =
  exports.unsafeMakeRef =
  exports.makeRef =
    void 0
// tracing: off
const Tp = __importStar(require("../Collections/Immutable/Tuple"))
const absolve = __importStar(require("../Effect/absolve"))
const E = __importStar(require("../Either"))
const Function_1 = require("../Function")
const O = __importStar(require("../Option"))
const AtomicReference_1 = require("../Support/AtomicReference")
const Utils_1 = require("../Utils")
const A = __importStar(require("./atomic"))
const T = __importStar(require("./effect"))
const XRef_1 = require("./XRef")
/**
 * Creates a new `XRef` with the specified value.
 */
function makeRef(a) {
  return T.succeedWith(
    () => new XRef_1.Atomic(new AtomicReference_1.AtomicReference(a))
  )
}
exports.makeRef = makeRef
/**
 * Creates a new `XRef` with the specified value.
 */
function unsafeMakeRef(a) {
  return new XRef_1.Atomic(new AtomicReference_1.AtomicReference(a))
}
exports.unsafeMakeRef = unsafeMakeRef
/**
 * Maps and filters the `get` value of the `XRef` with the specified partial
 * function, returning a `XRef` with a `get` value that succeeds with the
 * result of the partial function if it is defined or else fails with `None`.
 *
 * @dataFirst collect_
 */
function collect(pf) {
  return (self) => collect_(self, pf)
}
exports.collect = collect
/**
 * Maps and filters the `get` value of the `XRef` with the specified partial
 * function, returning a `XRef` with a `get` value that succeeds with the
 * result of the partial function if it is defined or else fails with `None`.
 */
function collect_(self, pf) {
  return self.fold(Function_1.identity, O.some, E.right, (b) =>
    E.fromOption_(pf(b), () => O.none)
  )
}
exports.collect_ = collect_
/**
 * Transforms the `set` value of the `XRef` with the specified function.
 *
 * @dataFirst contramap_
 */
function contramap(f) {
  return (self) => contramap_(self, f)
}
exports.contramap = contramap
/**
 * Transforms the `set` value of the `XRef` with the specified function.
 */
function contramap_(self, f) {
  return contramapEither_(self, (c) => E.right(f(c)))
}
exports.contramap_ = contramap_
/**
 * Transforms the `set` value of the `XRef` with the specified fallible
 * function.
 *
 * @dataFirst contramapEither_
 */
function contramapEither(f) {
  return (self) => contramapEither_(self, f)
}
exports.contramapEither = contramapEither
/**
 * Transforms the `set` value of the `XRef` with the specified fallible
 * function.
 */
function contramapEither_(self, f) {
  return dimapEither_(self, f, (x) => E.right(x))
}
exports.contramapEither_ = contramapEither_
/**
 * Transforms both the `set` and `get` values of the `XRef` with the
 * specified functions.
 *
 * @dataFirst dimap_
 */
function dimap(f, g) {
  return (self) => dimap_(self, f, g)
}
exports.dimap = dimap
/**
 * Transforms both the `set` and `get` values of the `XRef` with the
 * specified functions.
 */
function dimap_(self, f, g) {
  return dimapEither_(
    self,
    (c) => E.right(f(c)),
    (b) => E.right(g(b))
  )
}
exports.dimap_ = dimap_
/**
 * Transforms both the `set` and `get` values of the `XRef` with the
 * specified fallible functions.
 *
 * @dataFirst dimapEither_
 */
function dimapEither(f, g) {
  return (self) => dimapEither_(self, f, g)
}
exports.dimapEither = dimapEither
/**
 * Transforms both the `set` and `get` values of the `XRef` with the
 * specified fallible functions.
 */
function dimapEither_(self, f, g) {
  return self.fold(
    (ea) => ea,
    (eb) => eb,
    f,
    g
  )
}
exports.dimapEither_ = dimapEither_
/**
 * Transforms both the `set` and `get` errors of the `XRef` with the
 * specified functions.
 *
 * @dataFirst dimapError_
 */
function dimapError(f, g) {
  return (self) => dimapError_(self, f, g)
}
exports.dimapError = dimapError
/**
 * Transforms both the `set` and `get` errors of the `XRef` with the
 * specified functions.
 */
function dimapError_(self, f, g) {
  return self.fold(f, g, E.right, E.right)
}
exports.dimapError_ = dimapError_
/**
 * Filters the `set` value of the `XRef` with the specified predicate,
 * returning a `XRef` with a `set` value that succeeds if the predicate is
 * satisfied or else fails with `None`.
 *
 * @dataFirst filterInput_
 */
function filterInput(f) {
  return (self) => filterInput_(self, f)
}
exports.filterInput = filterInput
/**
 * Filters the `set` value of the `XRef` with the specified predicate,
 * returning a `XRef` with a `set` value that succeeds if the predicate is
 * satisfied or else fails with `None`.
 */
function filterInput_(self, f) {
  return self.fold(
    O.some,
    Function_1.identity,
    (a) => (f(a) ? E.right(a) : E.left(O.none)),
    E.right
  )
}
exports.filterInput_ = filterInput_
/**
 * Filters the `get` value of the `XRef` with the specified predicate,
 * returning a `XRef` with a `get` value that succeeds if the predicate is
 * satisfied or else fails with `None`.
 *
 * @dataFirst filterOutput_
 */
function filterOutput(f) {
  return (_) => filterOutput_(_, f)
}
exports.filterOutput = filterOutput
/**
 * Filters the `get` value of the `XRef` with the specified predicate,
 * returning a `XRef` with a `get` value that succeeds if the predicate is
 * satisfied or else fails with `None`.
 */
function filterOutput_(_, f) {
  return _.fold(Function_1.identity, O.some, E.right, (b) =>
    f(b) ? E.right(b) : E.left(O.none)
  )
}
exports.filterOutput_ = filterOutput_
/**
 * Transforms the `get` value of the `XRef` with the specified function.
 *
 * @dataFirst map_
 */
function map(f) {
  return (_) => map_(_, f)
}
exports.map = map
/**
 * Transforms the `get` value of the `XRef` with the specified function.
 */
function map_(_, f) {
  return mapEither_(_, (b) => E.right(f(b)))
}
exports.map_ = map_
/**
 * Transforms the `get` value of the `XRef` with the specified fallible
 * function.
 *
 * @dataFirst mapEither_
 */
function mapEither(f) {
  return (_) => mapEither_(_, f)
}
exports.mapEither = mapEither
/**
 * Transforms the `get` value of the `XRef` with the specified fallible
 * function.
 */
function mapEither_(_, f) {
  return dimapEither_(_, (a) => E.right(a), f)
}
exports.mapEither_ = mapEither_
/**
 * Returns a read only view of the `XRef`.
 *
 * @optimize identity
 */
function readOnly(_) {
  return _
}
exports.readOnly = readOnly
/**
 * Returns a write only view of the `XRef`.
 */
function writeOnly(_) {
  return _.fold(
    Function_1.identity,
    () => undefined,
    E.right,
    () => E.left(undefined)
  )
}
exports.writeOnly = writeOnly
/**
 * Atomically modifies the `XRef` with the specified function, which
 * computes a return value for the modification. This is a more powerful
 * version of `update`.
 *
 * @dataFirst modify_
 */
function modify(f) {
  return (self) => modify_(self, f)
}
exports.modify = modify
/**
 * Atomically modifies the `XRef` with the specified function, which
 * computes a return value for the modification. This is a more powerful
 * version of `update`.
 */
function modify_(self, f) {
  return (0, Utils_1.matchTag)({
    Atomic: (_) => A.modify(_, f),
    Derived: (self) =>
      self.use((value, getEither, setEither) =>
        absolve.absolve(
          A.modify(value, (s) =>
            E.fold_(
              getEither(s),
              (e) => Tp.tuple(E.left(e), s),
              (a1) =>
                (({ tuple: [b, a2] }) =>
                  E.fold_(
                    setEither(a2),
                    (e) => Tp.tuple(E.left(e), s),
                    (s) => Tp.tuple(E.right(b), s)
                  ))(f(a1))
            )
          )
        )
      ),
    DerivedAll: (self) =>
      self.use((value, getEither, setEither) =>
        absolve.absolve(
          A.modify(value, (s) =>
            E.fold_(
              getEither(s),
              (e) => Tp.tuple(E.left(e), s),
              (a1) =>
                (({ tuple: [b, a2] }) =>
                  E.fold_(
                    setEither(a2)(s),
                    (e) => Tp.tuple(E.left(e), s),
                    (s) => Tp.tuple(E.right(b), s)
                  ))(f(a1))
            )
          )
        )
      )
  })(self)
}
exports.modify_ = modify_
/**
 * Atomically modifies the `XRef` with the specified partial function,
 * which computes a return value for the modification if the function is
 * defined on the current value otherwise it returns a default value. This
 * is a more powerful version of `updateSome`.
 *
 * @dataFirst modifySome_
 */
function modifySome(def, f) {
  return (self) => modifySome_(self, def, f)
}
exports.modifySome = modifySome
/**
 * Atomically modifies the `XRef` with the specified partial function,
 * which computes a return value for the modification if the function is
 * defined on the current value otherwise it returns a default value. This
 * is a more powerful version of `updateSome`.
 */
function modifySome_(self, def, f) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.modifySome(_, def, f) }, (_) =>
    modify_(_, (a) => O.getOrElse_(f(a), () => Tp.tuple(def, a)))
  )(self)
}
exports.modifySome_ = modifySome_
/**
 * Atomically writes the specified value to the `XRef`, returning the value
 * immediately before modification.
 *
 * @dataFirst getAndSet_
 */
function getAndSet(a) {
  return (self) => getAndSet_(self, a)
}
exports.getAndSet = getAndSet
/**
 * Atomically writes the specified value to the `XRef`, returning the value
 * immediately before modification.
 */
function getAndSet_(self, a) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.getAndSet(_, a) }, (_) =>
    modify_(_, (v) => Tp.tuple(v, a))
  )(self)
}
exports.getAndSet_ = getAndSet_
/**
 * Atomically modifies the `XRef` with the specified function, returning
 * the value immediately before modification.
 *
 * @dataFirst getAndUpdate_
 */
function getAndUpdate(f) {
  return (self) => getAndUpdate_(self, f)
}
exports.getAndUpdate = getAndUpdate
/**
 * Atomically modifies the `XRef` with the specified function, returning
 * the value immediately before modification.
 */
function getAndUpdate_(self, f) {
  return (0, Utils_1.matchTag)(
    { Atomic: (_) => A.getAndUpdate(_, f) },
    modify((v) => Tp.tuple(v, f(v)))
  )(self)
}
exports.getAndUpdate_ = getAndUpdate_
/**
 * Atomically modifies the `XRef` with the specified partial function,
 * returning the value immediately before modification. If the function is
 * undefined on the current value it doesn't change it.
 *
 * @dataFirst getAndUpdateSome_
 */
function getAndUpdateSome(f) {
  return (self) => getAndUpdateSome_(self, f)
}
exports.getAndUpdateSome = getAndUpdateSome
/**
 * Atomically modifies the `XRef` with the specified partial function,
 * returning the value immediately before modification. If the function is
 * undefined on the current value it doesn't change it.
 */
function getAndUpdateSome_(self, f) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.getAndUpdateSome(_, f) }, (_) =>
    modify_(_, (v) => ((a) => Tp.tuple(v, a))(O.getOrElse(() => v)(f(v))))
  )(self)
}
exports.getAndUpdateSome_ = getAndUpdateSome_
/**
 * Atomically modifies the `XRef` with the specified function.
 *
 * @dataFirst update_
 */
function update(f) {
  return (self) => update_(self, f)
}
exports.update = update
/**
 * Atomically modifies the `XRef` with the specified function.
 */
function update_(self, f) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.update(_, f) }, (_) =>
    modify_(_, (v) => Tp.tuple(undefined, f(v)))
  )(self)
}
exports.update_ = update_
/**
 * Atomically modifies the `XRef` with the specified function and returns
 * the updated value.
 *
 * @dataFirst updateAndGet_
 */
function updateAndGet(f) {
  return (self) => updateAndGet_(self, f)
}
exports.updateAndGet = updateAndGet
/**
 * Atomically modifies the `XRef` with the specified function and returns
 * the updated value.
 */
function updateAndGet_(self, f) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.updateAndGet(_, f) }, (self) =>
    T.chain_(
      modify_(self, (v) => ((result) => Tp.tuple(result, result))(f(v))),
      () => self.get
    )
  )(self)
}
exports.updateAndGet_ = updateAndGet_
/**
 * Atomically modifies the `XRef` with the specified partial function. If
 * the function is undefined on the current value it doesn't change it.
 *
 * @dataFirst updateSome_
 */
function updateSome(f) {
  return (self) => updateSome_(self, f)
}
exports.updateSome = updateSome
/**
 * Atomically modifies the `XRef` with the specified partial function. If
 * the function is undefined on the current value it doesn't change it.
 */
function updateSome_(self, f) {
  return (0, Utils_1.matchTag)(
    { Atomic: (_) => A.updateSome(_, f) },
    modify((v) => ((a) => Tp.tuple(undefined, a))(O.getOrElse(() => v)(f(v))))
  )(self)
}
exports.updateSome_ = updateSome_
/**
 * Atomically modifies the `XRef` with the specified partial function. If
 * the function is undefined on the current value it returns the old value
 * without changing it.
 *
 * @dataFirst updateSomeAndGet_
 */
function updateSomeAndGet(f) {
  return (self) => updateSomeAndGet_(self, f)
}
exports.updateSomeAndGet = updateSomeAndGet
/**
 * Atomically modifies the `XRef` with the specified partial function. If
 * the function is undefined on the current value it returns the old value
 * without changing it.
 */
function updateSomeAndGet_(self, f) {
  return (0, Utils_1.matchTag)({ Atomic: (_) => A.updateSomeAndGet(_, f) }, (_) =>
    modify_(_, (v) =>
      ((result) => Tp.tuple(result, result))(O.getOrElse(() => v)(f(v)))
    )
  )(self)
}
exports.updateSomeAndGet_ = updateSomeAndGet_
/**
 * Folds over the error and value types of the `XRef`. This is a highly
 * polymorphic method that is capable of arbitrarily transforming the error
 * and value types of the `XRef`. For most use cases one of the more specific
 * combinators implemented in terms of `fold` will be more ergonomic but this
 * method is extremely useful for implementing new combinators.
 *
 * @dataFirst fold_
 */
function fold(ea, eb, ca, bd) {
  return (self) => self.fold(ea, eb, ca, bd)
}
exports.fold = fold
/**
 * Folds over the error and value types of the `XRef`. This is a highly
 * polymorphic method that is capable of arbitrarily transforming the error
 * and value types of the `XRef`. For most use cases one of the more specific
 * combinators implemented in terms of `fold` will be more ergonomic but this
 * method is extremely useful for implementing new combinators.
 */
function fold_(self, ea, eb, ca, bd) {
  return self.fold(ea, eb, ca, bd)
}
exports.fold_ = fold_
/**
 * Folds over the error and value types of the `XRef`, allowing access to
 * the state in transforming the `set` value. This is a more powerful version
 * of `fold` but requires unifying the error types.
 *
 * @dataFirst foldAll_
 */
function foldAll(ea, eb, ec, ca, bd) {
  return (self) => self.foldAll(ea, eb, ec, ca, bd)
}
exports.foldAll = foldAll
/**
 * Folds over the error and value types of the `XRef`, allowing access to
 * the state in transforming the `set` value. This is a more powerful version
 * of `fold` but requires unifying the error types.
 */
function foldAll_(self, ea, eb, ec, ca, bd) {
  return self.foldAll(ea, eb, ec, ca, bd)
}
exports.foldAll_ = foldAll_
/**
 * Reads the value from the `XRef`.
 */
function get(self) {
  return self.get
}
exports.get = get
/**
 * Writes a new value to the `XRef`, with a guarantee of immediate
 * consistency (at some cost to performance).
 *
 * @dataFirst set_
 */
function set(a) {
  return (self) => self.set(a)
}
exports.set = set
/**
 * Writes a new value to the `XRef`, with a guarantee of immediate
 * consistency (at some cost to performance).
 */
function set_(self, a) {
  return self.set(a)
}
exports.set_ = set_
//# sourceMappingURL=api.js.map
