"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.zipWithFiber = exports.zipRightFiber = exports.zipLeftFiber = exports.zipFiber = exports.updateSomeAndGetEffectSynchronized = exports.unsafeMakeSynchronized = exports.unsafeMakeSemaphore = exports.timeoutTo = exports.timeoutFailCause = exports.timeoutFail = exports.timeout = exports.synchronizedVariance = exports.supervised = exports.scheduleForked = exports.raceFirst = exports.memoizeFunction = exports.makeSynchronized = exports.makeSemaphore = exports.fromFiberEffect = exports.fromFiber = exports.forkScoped = exports.forkIn = exports.forkAll = exports.ensuringChildren = exports.ensuringChild = exports.cachedInvalidate = exports.cached = exports.awaitAllChildren = exports.SynchronizedTypeId = void 0;
var Duration = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Duration"));
var Either = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Either"));
var Equal = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Equal"));
var _Function = /*#__PURE__*/require("@effect/data/Function");
var Hash = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Hash"));
var MutableHashMap = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/MutableHashMap"));
var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Option"));
var _Pipeable = /*#__PURE__*/require("@effect/data/Pipeable");
var Predicate = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Predicate"));
var Exit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/Exit"));
var FiberId = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/Fiber/Id"));
var internalCause = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/cause"));
var core = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/core"));
var effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/effect"));
var executionStrategy = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/executionStrategy"));
var internalFiber = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/fiber"));
var fiberRuntime = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/fiberRuntime"));
var _fiberScope = /*#__PURE__*/require("@effect/io/internal/fiberScope");
var internalRef = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/ref"));
var _schedule = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/schedule"));
var supervisor = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal/supervisor"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var _a, _b, _c;
/** @internal */
class Semaphore {
  constructor(permits) {
    this.permits = permits;
    this.waiters = new Array();
    this.taken = 0;
    this.take = n => core.asyncEither(resume => {
      if (this.free < n) {
        const observer = () => {
          if (this.free >= n) {
            const observerIndex = this.waiters.findIndex(cb => cb === observer);
            if (observerIndex !== -1) {
              this.waiters.splice(observerIndex, 1);
            }
            this.taken += n;
            resume(core.succeed(n));
          }
        };
        this.waiters.push(observer);
        return Either.left(core.sync(() => {
          const observerIndex = this.waiters.findIndex(cb => cb === observer);
          if (observerIndex !== -1) {
            this.waiters.splice(observerIndex, 1);
          }
        }));
      }
      this.taken += n;
      return Either.right(core.succeed(n));
    });
    this.release = n => core.withFiberRuntime(fiber => {
      this.taken -= n;
      fiber.getFiberRef(core.currentScheduler).scheduleTask(() => {
        this.waiters.forEach(wake => wake());
      }, fiber.getFiberRef(core.currentSchedulingPriority));
      return core.unit;
    });
    this.withPermits = n => self => core.uninterruptibleMask(restore => core.flatMap(restore(this.take(n)), permits => fiberRuntime.ensuring(restore(self), this.release(permits))));
  }
  get free() {
    return this.permits - this.taken;
  }
}
/** @internal */
const unsafeMakeSemaphore = leases => {
  return new Semaphore(leases);
};
/** @internal */
exports.unsafeMakeSemaphore = unsafeMakeSemaphore;
const makeSemaphore = permits => core.sync(() => unsafeMakeSemaphore(permits));
/** @internal */
exports.makeSemaphore = makeSemaphore;
const awaitAllChildren = self => ensuringChildren(self, fiberRuntime.fiberAwaitAll);
/** @internal */
exports.awaitAllChildren = awaitAllChildren;
const cached = /*#__PURE__*/(0, _Function.dual)(2, (self, timeToLive) => core.map(cachedInvalidate(self, timeToLive), tuple => tuple[0]));
/** @internal */
exports.cached = cached;
const cachedInvalidate = /*#__PURE__*/(0, _Function.dual)(2, (self, timeToLive) => {
  const duration = Duration.decode(timeToLive);
  return core.flatMap(core.context(), env => core.map(makeSynchronized(Option.none()), cache => [core.provideContext(getCachedValue(self, duration, cache), env), invalidateCache(cache)]));
});
/** @internal */
exports.cachedInvalidate = cachedInvalidate;
const computeCachedValue = (self, timeToLive, start) => {
  const timeToLiveMillis = Duration.toMillis(Duration.decode(timeToLive));
  return core.map(deferred => Option.some([start + timeToLiveMillis, deferred]))(core.tap(deferred => core.intoDeferred(self, deferred))(core.deferredMake()));
};
/** @internal */
const getCachedValue = (self, timeToLive, cache) => core.uninterruptibleMask(restore => core.flatMap(option => Option.isNone(option) ? core.dieMessage("BUG: Effect.cachedInvalidate - please report an issue at https://github.com/Effect-TS/io/issues") : restore(core.deferredAwait(option.value[1])))(core.flatMap(time => updateSomeAndGetEffectSynchronized(cache, option => {
  switch (option._tag) {
    case "None":
      {
        return Option.some(computeCachedValue(self, timeToLive, time));
      }
    case "Some":
      {
        const [end] = option.value;
        return end - time <= 0 ? Option.some(computeCachedValue(self, timeToLive, time)) : Option.none();
      }
  }
}))(effect.clockWith(clock => clock.currentTimeMillis))));
/** @internal */
const invalidateCache = cache => internalRef.set(cache, Option.none());
/** @internal */
const ensuringChild = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => ensuringChildren(self, children => f(fiberRuntime.fiberAll(children))));
/** @internal */
exports.ensuringChild = ensuringChild;
const ensuringChildren = /*#__PURE__*/(0, _Function.dual)(2, (self, children) => core.flatMap(supervisor.track, supervisor => fiberRuntime.ensuring(core.flatMap(supervisor.value(), children))(supervised(self, supervisor))));
/** @internal */
// @ts-expect-error
exports.ensuringChildren = ensuringChildren;
const forkAll = /*#__PURE__*/(0, _Function.dual)(args => Predicate.isIterable(args[0]), (effects, options) => options?.discard ? core.forEachSequentialDiscard(effects, fiberRuntime.fork) : core.map(core.forEachSequential(effects, fiberRuntime.fork), fiberRuntime.fiberAll));
/** @internal */
exports.forkAll = forkAll;
const forkIn = /*#__PURE__*/(0, _Function.dual)(2, (self, scope) => core.uninterruptibleMask(restore => core.flatMap(scope.fork(executionStrategy.sequential), child => core.tap(fiber => child.addFinalizer(() => core.fiberIdWith(fiberId => Equal.equals(fiberId, fiber.id()) ? core.unit : core.asUnit(core.interruptFiber(fiber)))))(fiberRuntime.forkDaemon(core.onExit(exit => child.close(exit))(restore(self)))))));
/** @internal */
exports.forkIn = forkIn;
const forkScoped = self => fiberRuntime.scopeWith(scope => forkIn(self, scope));
/** @internal */
exports.forkScoped = forkScoped;
const fromFiber = fiber => internalFiber.join(fiber);
/** @internal */
exports.fromFiber = fromFiber;
const fromFiberEffect = fiber => core.suspend(() => core.flatMap(fiber, internalFiber.join));
exports.fromFiberEffect = fromFiberEffect;
const memoKeySymbol = /*#__PURE__*/Symbol.for("@effect/io/Effect/memoizeFunction.key");
class Key {
  constructor(a, eq) {
    this.a = a;
    this.eq = eq;
    this[_a] = memoKeySymbol;
  }
  [(_a = memoKeySymbol, Equal.symbol)](that) {
    if (typeof that === "object" && that !== null && memoKeySymbol in that) {
      if (this.eq) {
        return this.eq(this.a, that.a);
      } else {
        return Equal.equals(this.a, that.a);
      }
    }
    return false;
  }
  [Hash.symbol]() {
    return this.eq ? 0 : Hash.hash(this.a);
  }
}
/** @internal */
const memoizeFunction = (f, eq) => {
  return core.map(ref => a => core.flatMap(([patch, b]) => core.as(b)(effect.patchFiberRefs(patch)))(core.flatMap(core.deferredAwait)(ref.modifyEffect(map => {
    const result = MutableHashMap.get(new Key(a, eq))(map);
    if (Option.isNone(result)) {
      return core.map(deferred => [deferred, MutableHashMap.set(new Key(a, eq), deferred)(map)])(core.tap(deferred => fiberRuntime.fork(core.intoDeferred(deferred)(effect.diffFiberRefs(f(a)))))(core.deferredMake()));
    }
    return core.succeed([result.value, map]);
  }))))(core.flatMap(makeSynchronized)(core.sync(() => MutableHashMap.empty())));
};
/** @internal */
exports.memoizeFunction = memoizeFunction;
const raceFirst = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => (effect => core.flatten(effect))(fiberRuntime.race(core.exit(that))(core.exit(self))));
/** @internal */
exports.raceFirst = raceFirst;
const scheduleForked = /*#__PURE__*/(0, _Function.dual)(2, (self, schedule) => forkScoped(_schedule.schedule_Effect(schedule)(self)));
/** @internal */
exports.scheduleForked = scheduleForked;
const supervised = /*#__PURE__*/(0, _Function.dual)(2, (self, supervisor) => {
  const supervise = core.fiberRefLocallyWith(fiberRuntime.currentSupervisor, s => s.zip(supervisor));
  return supervise(self);
});
/** @internal */
exports.supervised = supervised;
const timeout = /*#__PURE__*/(0, _Function.dual)(2, (self, duration) => timeoutTo(self, {
  onTimeout: Option.none,
  onSuccess: Option.some,
  duration
}));
/** @internal */
exports.timeout = timeout;
const timeoutFail = /*#__PURE__*/(0, _Function.dual)(2, (self, {
  duration,
  onTimeout
}) => core.flatten(timeoutTo(self, {
  onTimeout: () => core.failSync(onTimeout),
  onSuccess: core.succeed,
  duration
})));
/** @internal */
exports.timeoutFail = timeoutFail;
const timeoutFailCause = /*#__PURE__*/(0, _Function.dual)(2, (self, {
  duration,
  onTimeout
}) => core.flatten(timeoutTo(self, {
  onTimeout: () => core.failCauseSync(onTimeout),
  onSuccess: core.succeed,
  duration
})));
/** @internal */
exports.timeoutFailCause = timeoutFailCause;
const timeoutTo = /*#__PURE__*/(0, _Function.dual)(2, (self, {
  duration,
  onSuccess,
  onTimeout
}) => core.fiberIdWith(parentFiberId => fiberRuntime.raceFibersWith(self, core.interruptible(effect.sleep(duration)), {
  onSelfWin: (winner, loser) => core.flatMap(winner.await(), exit => {
    if (exit._tag === "Success") {
      return core.flatMap(winner.inheritAll(), () => core.as(core.interruptAsFiber(loser, parentFiberId), onSuccess(exit.value)));
    } else {
      return core.flatMap(core.interruptAsFiber(loser, parentFiberId), () => core.exitFailCause(exit.cause));
    }
  }),
  onOtherWin: (winner, loser) => core.flatMap(winner.await(), exit => {
    if (exit._tag === "Success") {
      return core.flatMap(winner.inheritAll(), () => core.as(core.interruptAsFiber(loser, parentFiberId), onTimeout()));
    } else {
      return core.flatMap(core.interruptAsFiber(loser, parentFiberId), () => core.exitFailCause(exit.cause));
    }
  }),
  otherScope: _fiberScope.globalScope
})));
// circular with Synchronized
/** @internal */
exports.timeoutTo = timeoutTo;
const SynchronizedSymbolKey = "@effect/io/Ref/Synchronized";
/** @internal */
const SynchronizedTypeId = /*#__PURE__*/Symbol.for(SynchronizedSymbolKey);
/** @internal */
exports.SynchronizedTypeId = SynchronizedTypeId;
const synchronizedVariance = {
  _A: _ => _
};
/** @internal */
exports.synchronizedVariance = synchronizedVariance;
class SynchronizedImpl {
  constructor(ref, withLock) {
    this.ref = ref;
    this.withLock = withLock;
    this[_b] = synchronizedVariance;
    this[_c] = internalRef.refVariance;
  }
  modify(f) {
    return this.modifyEffect(a => core.succeed(f(a)));
  }
  modifyEffect(f) {
    return this.withLock(core.flatMap(([b, a]) => core.as(internalRef.set(this.ref, a), b))(core.flatMap(internalRef.get(this.ref), f)));
  }
  pipe() {
    return (0, _Pipeable.pipeArguments)(this, arguments);
  }
}
_b = SynchronizedTypeId, _c = internalRef.RefTypeId;
/** @internal */
const makeSynchronized = value => core.sync(() => unsafeMakeSynchronized(value));
/** @internal */
exports.makeSynchronized = makeSynchronized;
const unsafeMakeSynchronized = value => {
  const ref = internalRef.unsafeMake(value);
  const sem = unsafeMakeSemaphore(1);
  return new SynchronizedImpl(ref, sem.withPermits(1));
};
/** @internal */
exports.unsafeMakeSynchronized = unsafeMakeSynchronized;
const updateSomeAndGetEffectSynchronized = /*#__PURE__*/(0, _Function.dual)(2, (self, pf) => self.modifyEffect(value => {
  const result = pf(value);
  switch (result._tag) {
    case "None":
      {
        return core.succeed([value, value]);
      }
    case "Some":
      {
        return core.map(result.value, a => [a, a]);
      }
  }
}));
// circular with Fiber
/** @internal */
exports.updateSomeAndGetEffectSynchronized = updateSomeAndGetEffectSynchronized;
const zipFiber = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => zipWithFiber(self, that, (a, b) => [a, b]));
/** @internal */
exports.zipFiber = zipFiber;
const zipLeftFiber = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => zipWithFiber(self, that, (a, _) => a));
/** @internal */
exports.zipLeftFiber = zipLeftFiber;
const zipRightFiber = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => zipWithFiber(self, that, (_, b) => b));
/** @internal */
exports.zipRightFiber = zipRightFiber;
const zipWithFiber = /*#__PURE__*/(0, _Function.dual)(3, (self, that, f) => ({
  [internalFiber.FiberTypeId]: internalFiber.fiberVariance,
  id: () => FiberId.getOrElse(that.id())(self.id()),
  await: () => core.exit(fiberRuntime.zipWithOptions(core.flatten(that.await()), f, {
    concurrent: true
  })(core.flatten(self.await()))),
  children: () => self.children(),
  inheritAll: () => core.zipRight(that.inheritAll(), self.inheritAll()),
  poll: () => core.zipWith(self.poll(), that.poll(), (optionA, optionB) => Option.flatMap(exitA => Option.map(exitB => Exit.zipWith(exitA, exitB, {
    onSuccess: f,
    onFailure: internalCause.parallel
  }))(optionB))(optionA)),
  interruptAsFork: id => core.zipRight(self.interruptAsFork(id), that.interruptAsFork(id)),
  pipe() {
    return (0, _Pipeable.pipeArguments)(this, arguments);
  }
}));
exports.zipWithFiber = zipWithFiber;
//# sourceMappingURL=circular.js.map