const fileName_1 = "(@effect/core) _src/io/Hub/operations/strategy.ts";
import * as tsplus_module_1 from "@tsplus/stdlib/collections/mutable/MutableQueue";
import * as tsplus_module_2 from "@tsplus/stdlib/data/Tuple/make";
import * as tsplus_module_3 from "@tsplus/stdlib/collections/Chunk/prepend";
import * as tsplus_module_4 from "@tsplus/stdlib/collections/mutable/MutableQueue/unbounded";
import * as tsplus_module_5 from "@effect/core/io/Deferred/operations/unsafeMake";
import * as tsplus_module_6 from "@effect/core/io/Effect/operations/succeed";
import * as tsplus_module_7 from "@effect/core/io/Effect/operations/interruption";
import * as tsplus_module_8 from "@effect/core/io/Effect/operations/suspendSucceed";
import * as tsplus_module_9 from "@effect/core/io/Effect/operations/suspendSucceedWith";
import * as tsplus_module_10 from "@effect/core/io/Effect/operations/unit";
import * as tsplus_module_11 from "@effect/core/io/Effect/operations/excl-forEach";
import * as tsplus_module_12 from "@effect/core/io/Effect/operations/fiberId";
import * as tsplus_module_13 from "@effect/core/io/Effect/operations/do";
import * as tsplus_module_14 from "@effect/core/io/Effect/operations/tap";
import * as tsplus_module_15 from "@tsplus/stdlib/collections/Chunk/filter";
import { unsafeCompleteDeferred } from "@effect/core/io/Hub/operations/_internal/unsafeCompleteDeferred";
import { unsafeOfferAll } from "@effect/core/io/Hub/operations/_internal/unsafeOfferAll";
import { unsafePollAllQueue } from "@effect/core/io/Hub/operations/_internal/unsafePollAllQueue";
export const Strategy = {};

class BaseStrategy {
  unsafeCompletePollers(hub, subscribers, subscription, pollers) {
    let keepPolling = true;

    while (keepPolling && !subscription.isEmpty()) {
      const poller = pollers.poll(tsplus_module_1.EmptyMutableQueue);

      if (poller === tsplus_module_1.EmptyMutableQueue) {
        const subPollerPair = tsplus_module_2.make(subscription, pollers);
        subscribers.remove(subPollerPair);

        if (pollers.isEmpty) {
          keepPolling = false;
        } else {
          subscribers.add(subPollerPair);
        }
      } else {
        const pollResult = subscription.poll(tsplus_module_1.EmptyMutableQueue);

        if (pollResult == tsplus_module_1.EmptyMutableQueue) {
          unsafeOfferAll(pollers, tsplus_module_3.prepend_(unsafePollAllQueue(pollers), poller));
        } else {
          unsafeCompleteDeferred(poller, pollResult);
          this.unsafeOnHubEmptySpace(hub, subscribers);
        }
      }
    }
  }

  unsafeCompleteSubscribers(hub, subscribers) {
    for (const {
      tuple: [subscription, pollers]
    } of subscribers) {
      this.unsafeCompletePollers(hub, subscribers, subscription, pollers);
    }
  }

}
/**
 * A strategy that applies back pressure to publishers when the hub is at
 * capacity. This guarantees that all subscribers will receive all messages
 * published to the hub while they are subscribed. However, it creates the
 * risk that a slow subscriber will slow down the rate at which messages
 * are published and received by other subscribers.
 */


export class BackPressure extends BaseStrategy {
  constructor() {
    super(...arguments);
    this.publishers = tsplus_module_4.unbounded();
  }

  handleSurplus(hub, subscribers, as, isShutdown) {
    return tsplus_module_9.suspendSucceedWith((_, fiberId) => {
      const deferred = tsplus_module_5.unsafeMake(fiberId);
      return tsplus_module_7.onInterrupt_(tsplus_module_8.suspendSucceed(() => {
        this.unsafeOffer(as, deferred);
        this.unsafeOnHubEmptySpace(hub, subscribers);
        this.unsafeCompleteSubscribers(hub, subscribers);
        return isShutdown.get ? tsplus_module_7.interrupt : deferred.await(fileName_1 + ":154:66");
      }, fileName_1 + ":149:35"), () => tsplus_module_6.succeed(() => this.unsafeRemove(deferred), fileName_1 + ":155:42"), fileName_1 + ":155:21");
    }, fileName_1 + ":146:37");
  }

  get shutdown() {
    return tsplus_module_10.unit_(tsplus_module_14.tap_(tsplus_module_13.bind_(tsplus_module_13.bind_(tsplus_module_13.Do(), "fiberId", () => tsplus_module_12.fiberId, fileName_1 + ":161:12"), "publishers", () => tsplus_module_6.succeed(() => unsafePollAllQueue(this.publishers), fileName_1 + ":162:47"), fileName_1 + ":162:12"), ({
      fiberId,
      publishers
    }) => tsplus_module_11.forEachParDiscard(() => publishers, ([_, deferred, last]) => last ? deferred.interruptAs(() => fiberId, fileName_1 + ":166:63") : tsplus_module_10.unit, fileName_1 + ":164:33"), fileName_1 + ":163:11"), fileName_1 + ":169:12");
  }

  unsafeOnHubEmptySpace(hub, subscribers) {
    let keepPolling = true;

    while (keepPolling && !hub.isFull()) {
      const publisher = this.publishers.poll(tsplus_module_1.EmptyMutableQueue);

      if (publisher === tsplus_module_1.EmptyMutableQueue) {
        keepPolling = false;
      } else {
        const published = hub.publish(publisher[0]);

        if (published && publisher[2]) {
          unsafeCompleteDeferred(publisher[1], true);
        } else if (!published) {
          unsafeOfferAll(this.publishers, tsplus_module_3.prepend_(unsafePollAllQueue(this.publishers), publisher));
        }

        this.unsafeCompleteSubscribers(hub, subscribers);
      }
    }
  }

  unsafeOffer(as, deferred) {
    const it = as[Symbol.iterator]();
    let curr = it.next();

    if (!curr.done) {
      let next;

      while ((next = it.next()) && !next.done) {
        this.publishers.offer([curr.value, deferred, false]);
        curr = next;
      }

      this.publishers.offer([curr.value, deferred, true]);
    }
  }

  unsafeRemove(deferred) {
    unsafeOfferAll(this.publishers, tsplus_module_15.filter_(unsafePollAllQueue(this.publishers), ([_, a]) => a !== deferred));
  }

}
/**
 * A strategy that drops new messages when the hub is at capacity. This
 * guarantees that a slow subscriber will not slow down the rate at which
 * messages are published. However, it creates the risk that a slow
 * subscriber will slow down the rate at which messages are received by
 * other subscribers and that subscribers may not receive all messages
 * published to the hub while they are subscribed.
 */

export class Dropping extends BaseStrategy {
  constructor() {
    super(...arguments);
    this.shutdown = tsplus_module_10.unit;
  }

  handleSurplus(_hub, _subscribers, _as, _isShutdown) {
    return tsplus_module_6.succeed(() => false, fileName_1 + ":236:26");
  }

  unsafeOnHubEmptySpace(_hub, _subscribers) {//
  }

}
/**
 * A strategy that adds new messages and drops old messages when the hub is
 * at capacity. This guarantees that a slow subscriber will not slow down
 * the rate at which messages are published and received by other
 * subscribers. However, it creates the risk that a slow subscriber will
 * not receive some messages published to the hub while it is subscribed.
 */

export class Sliding extends BaseStrategy {
  constructor() {
    super(...arguments);
    this.shutdown = tsplus_module_10.unit;
  }

  unsafeSlidingPublish(hub, as) {
    const it = as[Symbol.iterator]();
    let next = it.next();

    if (!next.done && hub.capacity > 0) {
      let a = next.value;
      let loop = true;

      while (loop) {
        hub.slide();
        const pub = hub.publish(a);

        if (pub && (next = it.next()) && !next.done) {
          a = next.value;
        } else if (pub) {
          loop = false;
        }
      }
    }
  }

  handleSurplus(hub, subscribers, as, _isShutdown) {
    return tsplus_module_6.succeed(() => {
      this.unsafeSlidingPublish(hub, as);
      this.unsafeCompleteSubscribers(hub, subscribers);
      return true;
    }, fileName_1 + ":282:26");
  }

  unsafeOnHubEmptySpace(_hub, _subscribers) {//
  }

}
/**
 * @tsplus static ets/Hub/StrategyOps BackPressure
 */

export function backPressureStrategy() {
  return new BackPressure();
}
/**
 * @tsplus static ets/Hub/StrategyOps Dropping
 */

export function droppingStrategy() {
  return new Dropping();
}
/**
 * @tsplus static ets/Hub/StrategyOps Sliding
 */

export function slidingStrategy() {
  return new Sliding();
}
//# sourceMappingURL=strategy.mjs.map