const fileName_1 = "(@effect/core) _src/stream/Channel/ChannelExecutor.ts";
import * as tsplus_module_1 from "@tsplus/stdlib/collections/List/empty";
import * as tsplus_module_2 from "@effect/core/io/Effect/operations/unit";
import * as tsplus_module_3 from "@tsplus/stdlib/collections/List/definition";
import * as tsplus_module_4 from "@tsplus/stdlib/collections/List/unsafeHead";
import * as tsplus_module_5 from "@tsplus/stdlib/collections/List/unsafeTail";
import * as tsplus_module_6 from "@effect/core/io/Effect/operations/exit";
import * as tsplus_module_7 from "@effect/core/io/Effect/operations/zipRight";
import * as tsplus_module_8 from "@effect/core/io/Effect/operations/done";
import * as tsplus_module_9 from "@effect/core/io/Exit/operations/unit";
import * as tsplus_module_10 from "@effect/core/io/Effect/operations/succeed";
import * as tsplus_module_11 from "@effect/core/io/Effect/operations/flatMap";
import * as tsplus_module_12 from "@tsplus/stdlib/collections/mutable/ListBuffer";
import * as tsplus_module_13 from "@tsplus/stdlib/collections/List/from";
import * as tsplus_module_14 from "@effect/core/io/Effect/operations/ensuring";
import * as tsplus_module_15 from "@effect/core/io/Exit/operations/zipRight";
import * as tsplus_module_16 from "@effect/core/io/Effect/operations/tuple";
import * as tsplus_module_17 from "@effect/core/io/Effect/operations/map";
import * as tsplus_module_18 from "@effect/core/io/Effect/operations/interruption";
import * as tsplus_module_19 from "@effect/core/stream/Channel/ChannelState";
import * as tsplus_module_20 from "@effect/core/io/Exit/operations/fold";
import * as tsplus_module_21 from "@effect/core/io/Effect/operations/foldCauseEffect";
import * as tsplus_module_22 from "@effect/core/io/Effect/operations/catchAllCause";
import * as tsplus_module_23 from "@effect/core/io/Effect/operations/suspendSucceed";
import * as tsplus_module_24 from "@effect/core/io/Fiber/operations/interrupt";
import * as tsplus_module_25 from "@effect/core/io/Effect/operations/fork";
import * as tsplus_module_26 from "@tsplus/stdlib/data/Function";
import * as tsplus_module_27 from "@effect/core/io/Effect/operations/provideEnvironment";
import * as tsplus_module_28 from "@tsplus/stdlib/collections/ImmutableQueue/empty";
import * as tsplus_module_29 from "@effect/core/stream/Channel/Subexecutor";
import * as tsplus_module_30 from "@tsplus/stdlib/collections/List/prepend";
import * as tsplus_module_31 from "@effect/core/io/Cause/definition";
import * as tsplus_module_32 from "@effect/core/stream/Channel/operations/failCause";
import * as tsplus_module_33 from "@effect/core/io/Exit/operations/succeed";
import * as tsplus_module_34 from "@tsplus/stdlib/collections/List/map";
import * as tsplus_module_35 from "@effect/core/io/Exit/operations/failCause";
import * as tsplus_module_36 from "@effect/core/io/Exit/operations/collectAll";
import * as tsplus_module_37 from "@effect/core/io/Effect/operations/excl-forEach";
import * as tsplus_module_38 from "@tsplus/stdlib/collections/ImmutableQueue/find";
import * as tsplus_module_39 from "@tsplus/stdlib/data/Maybe/definition";
import * as tsplus_module_40 from "@tsplus/stdlib/collections/ImmutableQueue/prepend";
import * as tsplus_module_41 from "@tsplus/stdlib/data/Tuple/make";
import * as tsplus_module_42 from "@tsplus/stdlib/collections/ImmutableQueue/append";
import * as tsplus_module_43 from "@effect/core/stream/Channel/UpstreamPullRequest";
import * as tsplus_module_44 from "@effect/core/io/Exit/operations/map";
import * as tsplus_module_45 from "@tsplus/stdlib/collections/ImmutableQueue/dequeue";
import * as tsplus_module_46 from "@tsplus/stdlib/data/Maybe/fold";
import * as tsplus_module_47 from "@tsplus/stdlib/collections/Collection/functions";
import * as tsplus_module_48 from "@tsplus/stdlib/data/Stack";
import { concreteChannelState } from "@effect/core/stream/Channel/ChannelState";
import { concrete, concreteContinuation, ContinuationFinalizer, Emit, Fail, SucceedNow } from "@effect/core/stream/Channel/definition/primitives";
import { concreteSubexecutor } from "@effect/core/stream/Channel/Subexecutor";
export class ChannelExecutor {
  constructor(initialChannel, providedEnv, executeCloseLastSubstream) {
    this.providedEnv = providedEnv;
    this.executeCloseLastSubstream = executeCloseLastSubstream;
    this.done = undefined;
    this.doneStack = tsplus_module_1.empty();
    this.emitted = undefined;
    this.inProgressFinalizer = undefined;
    this.input = undefined;
    this.activeSubexecutor = undefined;
    this.cancelled = undefined;
    this.closeLastSubstream = undefined;
    this.currentChannel = initialChannel();
  }

  restorePipe(exit, prev, __tsplusTrace) {
    const currInput = this.input;
    this.input = prev;
    return currInput != null ? currInput.close(exit, fileName_1 + ":86:47") : tsplus_module_2.unit;
  }

  unwindAllFinalizers(acc, conts, exit) {
    while (tsplus_module_3.length(conts) !== 0) {
      const head = tsplus_module_4.unsafeHead(conts);
      void 0;

      if (head._tag === "ContinuationK") {
        conts = tsplus_module_5.unsafeTail(conts) ?? tsplus_module_1.empty();
      } else {
        acc = tsplus_module_7.zipRight_(acc, () => tsplus_module_6.exit(head.finalizer(exit), fileName_1 + ":100:46"), fileName_1 + ":100:20");
        conts = tsplus_module_5.unsafeTail(conts) ?? tsplus_module_1.empty();
      }
    }

    return acc;
  }

  popAllFinalizers(exit, __tsplusTrace) {
    const effect = tsplus_module_11.flatMap_(this.unwindAllFinalizers(tsplus_module_10.succeed(() => tsplus_module_9.unit, fileName_1 + ":112:21"), this.doneStack, exit), exit => tsplus_module_8.done(() => exit, fileName_1 + ":115:36"), fileName_1 + ":115:14");
    this.doneStack = tsplus_module_1.empty();
    this.storeInProgressFinalizer(effect);
    return effect;
  }

  popNextFinalizersGo(stack, builder) {
    while (tsplus_module_3.length(stack) > 0) {
      const head = tsplus_module_4.unsafeHead(stack);
      void 0;

      if (head._tag === "ContinuationK") {
        return stack;
      }

      builder.append(head);
      stack = tsplus_module_5.unsafeTail(stack) ?? tsplus_module_1.empty();
    }

    return tsplus_module_1.empty();
  }

  popNextFinalizers() {
    const builder = tsplus_module_12.ListBuffer.empty();
    this.doneStack = this.popNextFinalizersGo(this.doneStack, builder);
    return tsplus_module_13.from(builder);
  }

  storeInProgressFinalizer(finalizer) {
    this.inProgressFinalizer = finalizer;
  }

  clearInProgressFinalizer() {
    this.inProgressFinalizer = undefined;
  }

  ifNotNull(effect) {
    return effect != null ? effect : tsplus_module_2.unit;
  }

  close(exit, __tsplusTrace) {
    let runInProgressFinalizers = undefined;
    const finalizer = this.inProgressFinalizer;

    if (finalizer != null) {
      runInProgressFinalizers = tsplus_module_14.ensuring_(finalizer, () => tsplus_module_10.succeed(() => this.clearInProgressFinalizer(), fileName_1 + ":163:23"), fileName_1 + ":162:51");
    }

    const closeSubexecutors = this.activeSubexecutor == null ? undefined : this.activeSubexecutor.close(exit, fileName_1 + ":167:104");
    let closeSelf = undefined;
    const selfFinalizers = this.popAllFinalizers(exit, fileName_1 + ":170:49");

    if (selfFinalizers != null) {
      closeSelf = tsplus_module_14.ensuring_(selfFinalizers, () => tsplus_module_10.succeed(() => this.clearInProgressFinalizer(), fileName_1 + ":173:23"), fileName_1 + ":172:42");
    }

    if (closeSubexecutors == null && runInProgressFinalizers == null && closeSelf == null) {
      return undefined;
    }

    return tsplus_module_11.flatMap_(tsplus_module_18.uninterruptible(tsplus_module_17.map_(tsplus_module_16.tuple(tsplus_module_6.exit(this.ifNotNull(closeSubexecutors), fileName_1 + ":186:45"), tsplus_module_6.exit(this.ifNotNull(runInProgressFinalizers), fileName_1 + ":187:51"), tsplus_module_6.exit(this.ifNotNull(closeSelf), fileName_1 + ":188:37")), ({
      tuple: [a, b, c]
    }) => tsplus_module_15.zipRight_(tsplus_module_15.zipRight_(a, b), c), fileName_1 + ":190:11"), fileName_1 + ":191:23"), exit => tsplus_module_8.done(() => exit, fileName_1 + ":192:37"), fileName_1 + ":192:15");
  }

  getDone() {
    return this.done;
  }

  getEmit() {
    return this.emitted;
  }

  cancelWith(exit) {
    this.cancelled = exit;
  }

  run() {
    let result = undefined;

    while (result == null) {
      if (this.cancelled != null) {
        result = this.processCancellation();
      } else if (this.activeSubexecutor != null) {
        result = this.runSubexecutor(fileName_1 + ":214:37");
      } else {
        if (this.currentChannel == null) {
          result = tsplus_module_19.channelStateDone;
        } else {
          try {
            const currentChannel = this.currentChannel;
            void 0;

            switch (currentChannel._tag) {
              case "Bridge":
                {
                  // PipeTo(left, Bridge(queue, channel))
                  // In a fiber: repeatedly run left and push its outputs to the queue
                  // Add a finalizer to interrupt the fiber and close the executor
                  this.currentChannel = currentChannel.channel;

                  if (this.input != null) {
                    const inputExecutor = this.input;
                    this.input = undefined;
                    const drainer = tsplus_module_7.zipRight_(currentChannel.input.awaitRead, () => tsplus_module_23.suspendSucceed(() => {
                      const state = inputExecutor.run();
                      void 0;

                      switch (state._tag) {
                        case "Done":
                          {
                            return tsplus_module_20.fold_(inputExecutor.getDone(), cause => currentChannel.input.error(cause), value => currentChannel.input.done(value));
                          }

                        case "Emit":
                          {
                            return tsplus_module_7.zipRight_(currentChannel.input.emit(inputExecutor.getEmit()), () => drainer, fileName_1 + ":249:38");
                          }

                        case "Effect":
                          {
                            return tsplus_module_21.foldCauseEffect_(state.effect, cause => currentChannel.input.error(cause), () => drainer, fileName_1 + ":252:62");
                          }

                        case "Read":
                          {
                            return tsplus_module_22.catchAllCause_(readUpstream(state, () => drainer, fileName_1 + ":258:46"), cause => currentChannel.input.error(cause), fileName_1 + ":258:76");
                          }
                      }
                    }, fileName_1 + ":236:42"), fileName_1 + ":235:91");
                    result = tsplus_module_19.channelStateEffect(tsplus_module_11.flatMap_(tsplus_module_25.fork(drainer, fileName_1 + ":266:33"), fiber => tsplus_module_10.succeed(() => this.addFinalizer(exit => tsplus_module_7.zipRight_(tsplus_module_24.interrupt(fiber, fileName_1 + ":270:44"), () => tsplus_module_23.suspendSucceed(() => {
                      const effect = this.restorePipe(exit, inputExecutor, fileName_1 + ":272:64");
                      return effect != null ? effect : tsplus_module_2.unit;
                    }, fileName_1 + ":271:52"), fileName_1 + ":270:48")), fileName_1 + ":267:37"), fileName_1 + ":266:43"));
                  }

                  break;
                }

              case "PipeTo":
                {
                  const previousInput = this.input;
                  const leftExec = new ChannelExecutor(currentChannel.left, this.providedEnv, effect => this.executeCloseLastSubstream(effect));
                  leftExec.input = previousInput;
                  this.input = leftExec;
                  this.addFinalizer(exit => {
                    const effect = this.restorePipe(exit, previousInput, fileName_1 + ":296:50");
                    return effect != null ? effect : tsplus_module_2.unit;
                  });
                  this.currentChannel = currentChannel.right();
                  break;
                }

              case "Read":
                {
                  result = tsplus_module_19.channelStateRead(this.input, tsplus_module_26.identity, out => {
                    this.currentChannel = currentChannel.more(out);
                    return undefined;
                  }, exit => {
                    this.currentChannel = currentChannel.done.onExit(exit);
                    return undefined;
                  });
                  break;
                }

              case "SucceedNow":
                {
                  result = this.doneSucceed(currentChannel.terminal);
                  break;
                }

              case "Fail":
                {
                  result = this.doneHalt(currentChannel.error());
                  break;
                }

              case "Succeed":
                {
                  result = this.doneSucceed(currentChannel.effect());
                  break;
                }

              case "Suspend":
                {
                  this.currentChannel = currentChannel.effect();
                  break;
                }

              case "FromEffect":
                {
                  const peffect = this.providedEnv != null ? tsplus_module_27.provideEnvironment_(currentChannel.effect(), () => this.providedEnv, fileName_1 + ":346:40") : currentChannel.effect();
                  result = tsplus_module_19.channelStateEffect(tsplus_module_21.foldCauseEffect_(peffect, cause => {
                    const state = this.doneHalt(cause);

                    if (state == null) {
                      return tsplus_module_2.unit;
                    }

                    return tsplus_module_19.effectOrUnit(state, fileName_1 + ":356:48");
                  }, a => {
                    const state = this.doneSucceed(a);

                    if (state == null) {
                      return tsplus_module_2.unit;
                    }

                    return tsplus_module_19.effectOrUnit(state, fileName_1 + ":363:48");
                  }, fileName_1 + ":350:42"));
                  break;
                }

              case "Emit":
                {
                  this.emitted = currentChannel.out();
                  this.currentChannel = this.activeSubexecutor != null ? undefined : new SucceedNow(undefined);
                  result = tsplus_module_19.channelStateEmit;
                  break;
                }

              case "Ensuring":
                {
                  this.runEnsuring(currentChannel);
                  break;
                }

              case "ConcatAll":
                {
                  const executor = new ChannelExecutor(currentChannel.value, this.providedEnv, effect => tsplus_module_10.succeed(() => {
                    const prevLastClose = this.closeLastSubstream == null ? tsplus_module_2.unit : this.closeLastSubstream;
                    this.closeLastSubstream = tsplus_module_7.zipRight_(prevLastClose, () => effect, fileName_1 + ":392:64");
                  }, fileName_1 + ":388:35"));
                  executor.input = this.input;
                  this.activeSubexecutor = tsplus_module_29.pullFromUpstream(executor, currentChannel.k, undefined, tsplus_module_28.empty(), currentChannel.combineInners, currentChannel.combineAll, currentChannel.onPull, currentChannel.onEmit);
                  this.closeLastSubstream = undefined;
                  this.currentChannel = undefined;
                  break;
                }

              case "Fold":
                {
                  this.doneStack = tsplus_module_30.prepend_(this.doneStack, currentChannel.k);
                  this.currentChannel = currentChannel.value;
                  break;
                }

              case "BracketOut":
                {
                  result = this.runBracketOut(currentChannel);
                  break;
                }

              case "Provide":
                {
                  const previousEnv = this.providedEnv;
                  this.providedEnv = currentChannel.env();
                  this.currentChannel = currentChannel.channel;
                  this.addFinalizer(() => tsplus_module_10.succeed(() => {
                    this.providedEnv = previousEnv;
                  }, fileName_1 + ":431:33"));
                  break;
                }
            }
          } catch (error) {
            this.currentChannel = tsplus_module_32.failCause(() => tsplus_module_31.die(error));
          }
        }
      }
    }

    return result;
  }

  doneSucceed(z) {
    if (tsplus_module_3.length(this.doneStack) === 0) {
      this.done = tsplus_module_33.succeed(z);
      this.currentChannel = undefined;
      return tsplus_module_19.channelStateDone;
    }

    const head = tsplus_module_4.unsafeHead(this.doneStack);
    void 0;

    if (head._tag === "ContinuationK") {
      this.doneStack = tsplus_module_5.unsafeTail(this.doneStack) ?? tsplus_module_1.empty();
      this.currentChannel = head.onSuccess(z);
      return undefined;
    }

    const finalizers = this.popNextFinalizers();

    if (tsplus_module_3.length(this.doneStack) === 0) {
      this.doneStack = finalizers;
      this.done = tsplus_module_33.succeed(z);
      this.currentChannel = undefined;
      return tsplus_module_19.channelStateDone;
    }

    const finalizerEffect = this.runFinalizers(tsplus_module_34.map_(finalizers, _ => _.finalizer), tsplus_module_33.succeed(z), fileName_1 + ":474:47");
    this.storeInProgressFinalizer(finalizerEffect);
    return tsplus_module_19.channelStateEffect(tsplus_module_7.zipRight_(tsplus_module_18.uninterruptible(tsplus_module_14.ensuring_(finalizerEffect, () => tsplus_module_10.succeed(() => this.clearInProgressFinalizer(), fileName_1 + ":483:33"), fileName_1 + ":483:18"), fileName_1 + ":484:25"), () => tsplus_module_10.succeed(() => this.doneSucceed(z), fileName_1 + ":484:44"), fileName_1 + ":484:29"));
  }

  doneHalt(cause) {
    if (tsplus_module_3.length(this.doneStack) === 0) {
      this.done = tsplus_module_35.failCause(cause);
      this.currentChannel = undefined;
      return tsplus_module_19.channelStateDone;
    }

    const head = tsplus_module_4.unsafeHead(this.doneStack);
    void 0;

    if (head._tag === "ContinuationK") {
      this.doneStack = tsplus_module_5.unsafeTail(this.doneStack) ?? tsplus_module_1.empty();
      this.currentChannel = head.onHalt(cause);
      return undefined;
    }

    const finalizers = this.popNextFinalizers();

    if (tsplus_module_3.length(this.doneStack) === 0) {
      this.doneStack = finalizers;
      this.done = tsplus_module_35.failCause(cause);
      this.currentChannel = undefined;
      return tsplus_module_19.channelStateDone;
    }

    const finalizerEffect = this.runFinalizers(tsplus_module_34.map_(finalizers, _ => _.finalizer), tsplus_module_35.failCause(cause), fileName_1 + ":513:47");
    this.storeInProgressFinalizer(finalizerEffect);
    return tsplus_module_19.channelStateEffect(tsplus_module_7.zipRight_(tsplus_module_18.uninterruptible(tsplus_module_14.ensuring_(finalizerEffect, () => tsplus_module_10.succeed(() => this.clearInProgressFinalizer(), fileName_1 + ":522:33"), fileName_1 + ":522:18"), fileName_1 + ":523:25"), () => tsplus_module_10.succeed(() => this.doneHalt(cause), fileName_1 + ":524:33"), fileName_1 + ":524:18"));
  }

  processCancellation() {
    this.currentChannel = undefined;
    this.done = this.cancelled;
    this.cancelled = undefined;
    return tsplus_module_19.channelStateDone;
  }

  runBracketOut(bracketOut) {
    return tsplus_module_19.channelStateEffect(tsplus_module_18.uninterruptibleMask(({
      restore
    }) => tsplus_module_21.foldCauseEffect_(restore(() => this.provide(bracketOut.acquire(), fileName_1 + ":540:29"), fileName_1 + ":540:16"), cause => tsplus_module_10.succeed(() => {
      this.currentChannel = new Fail(() => cause);
    }, fileName_1 + ":542:27"), out => tsplus_module_10.succeed(() => {
      this.addFinalizer(exit => bracketOut.finalizer(out, exit));
      this.currentChannel = new Emit(() => out);
    }, fileName_1 + ":546:27"), fileName_1 + ":540:68"), fileName_1 + ":539:33"));
  }

  provide(effect, __tsplusTrace) {
    return this.providedEnv == null ? effect : tsplus_module_27.provideEnvironment_(effect, () => this.providedEnv, fileName_1 + ":561:34");
  }

  runEnsuring(ensuring) {
    this.addFinalizer(ensuring.finalizer);
    this.currentChannel = ensuring.channel;
  }

  addFinalizer(f) {
    this.doneStack = tsplus_module_30.prepend_(this.doneStack, new ContinuationFinalizer(f));
  }

  runFinalizers(finalizers, exit, __tsplusTrace) {
    return tsplus_module_3.length(finalizers) === 0 ? undefined : tsplus_module_11.flatMap_(tsplus_module_17.map_(tsplus_module_37.forEach(() => finalizers, f => tsplus_module_6.exit(f(exit), fileName_1 + ":582:55"), fileName_1 + ":582:23"), results => {
      const result = tsplus_module_36.collectAll(results);

      if (result._tag === "Some") {
        return result.value;
      }

      return tsplus_module_9.unit;
    }, fileName_1 + ":583:13"), exit => tsplus_module_8.done(() => exit, fileName_1 + ":590:39"), fileName_1 + ":590:17");
  }

  runSubexecutor(__tsplusTrace) {
    const subexecutor = this.activeSubexecutor;
    void 0;

    switch (subexecutor._tag) {
      case "PullFromUpstream":
        {
          return this.pullFromUpstream(subexecutor);
        }

      case "PullFromChild":
        {
          return this.pullFromChild(subexecutor.childExecutor, subexecutor.parentSubexecutor, subexecutor.onEmit, subexecutor);
        }

      case "DrainChildExecutors":
        {
          return this.drainChildExecutors(subexecutor);
        }

      case "Emit":
        {
          this.emitted = subexecutor.value;
          this.activeSubexecutor = subexecutor.next;
          return tsplus_module_19.channelStateEmit;
        }
    }
  }

  replaceSubexecutor(nextSubExecutor) {
    this.currentChannel = undefined;
    this.activeSubexecutor = nextSubExecutor;
  }

  finishSubexecutorWithCloseEffect(subexecutorDone, ...closeFns) {
    this.addFinalizer(() => tsplus_module_37.forEachDiscard(() => closeFns, closeFn => tsplus_module_11.flatMap_(tsplus_module_10.succeed(() => closeFn(subexecutorDone), fileName_1 + ":634:25"), closeEffect => closeEffect != null ? closeEffect : tsplus_module_2.unit, fileName_1 + ":634:59"), fileName_1 + ":631:28"));
    const state = tsplus_module_20.fold_(subexecutorDone, cause => this.doneHalt(cause), a => this.doneSucceed(a));
    this.activeSubexecutor = undefined;
    return state;
  }

  finishWithExit(exit, __tsplusTrace) {
    const state = tsplus_module_20.fold_(exit, cause => this.doneHalt(cause), a => this.doneSucceed(a));
    this.activeSubexecutor = undefined;
    return state == null ? tsplus_module_2.unit : tsplus_module_19.effectOrUnit(state, fileName_1 + ":657:60");
  }

  applyUpstreamPullStrategy(upstreamFinished, queue, strategy) {
    switch (strategy._tag) {
      case "PullAfterNext":
        {
          return tsplus_module_41.make(strategy.emitSeparator, !upstreamFinished || tsplus_module_39.isSome(tsplus_module_38.find_(queue, a => a != null)) ? tsplus_module_40.prepend_(queue, undefined) : queue);
        }

      case "PullAfterAllEnqueued":
        {
          return tsplus_module_41.make(strategy.emitSeparator, !upstreamFinished || tsplus_module_39.isSome(tsplus_module_38.find_(queue, a => a != null)) ? tsplus_module_42.append_(queue, undefined) : queue);
        }
    }
  }

  performPullFromUpstream(self) {
    return tsplus_module_19.channelStateRead(self.upstreamExecutor, effect => {
      const closeLast = this.closeLastSubstream == null ? tsplus_module_2.unit : this.closeLastSubstream;
      this.closeLastSubstream = undefined;
      return tsplus_module_7.zipRight_(this.executeCloseLastSubstream(closeLast), () => effect, fileName_1 + ":693:59");
    }, emitted => {
      if (this.closeLastSubstream != null) {
        const closeLast = this.closeLastSubstream;
        this.closeLastSubstream = undefined;
        return tsplus_module_17.map_(this.executeCloseLastSubstream(closeLast), () => {
          const childExecutor = new ChannelExecutor(() => self.createChild(emitted), this.providedEnv, effect => this.executeCloseLastSubstream(effect));
          childExecutor.input = this.input;
          const {
            tuple: [emitSeparator, updatedChildExecutors]
          } = this.applyUpstreamPullStrategy(false, self.activeChildExecutors, self.onPull(tsplus_module_43.pulled(emitted)));
          this.activeSubexecutor = tsplus_module_29.pullFromChild(childExecutor, tsplus_module_29.pullFromUpstream(self.upstreamExecutor, self.createChild, self.lastDone, updatedChildExecutors, self.combineChildResults, self.combineWithChildResult, self.onPull, self.onEmit), self.onEmit);

          if (tsplus_module_39.isSome(emitSeparator)) {
            this.activeSubexecutor = tsplus_module_29.emit(emitSeparator.value, this.activeSubexecutor);
          }

          return undefined;
        }, fileName_1 + ":700:63");
      } else {
        const childExecutor = new ChannelExecutor(() => self.createChild(emitted), this.providedEnv, effect => this.executeCloseLastSubstream(effect));
        childExecutor.input = this.input;
        const {
          tuple: [emitSeparator, updatedChildExecutors]
        } = this.applyUpstreamPullStrategy(false, self.activeChildExecutors, self.onPull(tsplus_module_43.pulled(emitted)));
        this.activeSubexecutor = tsplus_module_29.pullFromChild(childExecutor, tsplus_module_29.pullFromUpstream(self.upstreamExecutor, self.createChild, self.lastDone, updatedChildExecutors, self.combineChildResults, self.combineWithChildResult, self.onPull, self.onEmit), self.onEmit);

        if (tsplus_module_39.isSome(emitSeparator)) {
          this.activeSubexecutor = tsplus_module_29.emit(emitSeparator.value, this.activeSubexecutor);
        }

        return undefined;
      }
    }, exit => {
      if (tsplus_module_39.isSome(tsplus_module_38.find_(self.activeChildExecutors, a => a != null))) {
        const drain = tsplus_module_29.drainChildExecutors(self.upstreamExecutor, self.lastDone, tsplus_module_40.prepend_(self.activeChildExecutors, undefined), self.upstreamExecutor.getDone(), self.combineChildResults, self.combineWithChildResult, self.onPull);

        if (this.closeLastSubstream != null) {
          const closeLast = this.closeLastSubstream;
          this.closeLastSubstream = undefined;
          tsplus_module_17.map_(this.executeCloseLastSubstream(closeLast), () => this.replaceSubexecutor(drain), fileName_1 + ":796:58");
          return undefined;
        }

        this.replaceSubexecutor(drain);
        return undefined;
      } else {
        const lastClose = this.closeLastSubstream;
        const state = this.finishSubexecutorWithCloseEffect(tsplus_module_44.map_(exit, a => self.combineWithChildResult(self.lastDone, a)), () => lastClose, exit => self.upstreamExecutor.close(exit, fileName_1 + ":808:50"));
        return state != null ? tsplus_module_19.effectOrUndefinedIgnored(state, fileName_1 + ":810:64") : undefined;
      }
    });
  }

  pullFromUpstream(self) {
    return tsplus_module_46.fold_(tsplus_module_45.dequeue(self.activeChildExecutors), () => this.performPullFromUpstream(self), ({
      tuple: [activeChild, rest]
    }) => {
      const parentSubexecutor = tsplus_module_29.pullFromUpstream(self.upstreamExecutor, self.createChild, self.lastDone, rest, self.combineChildResults, self.combineWithChildResult, self.onPull, self.onEmit);

      if (activeChild == null) {
        return this.performPullFromUpstream(parentSubexecutor);
      }

      this.replaceSubexecutor(tsplus_module_29.pullFromChild(activeChild.childExecutor, parentSubexecutor, activeChild.onEmit));
      return undefined;
    });
  }

  drainChildExecutors(self) {
    return tsplus_module_46.fold_(tsplus_module_45.dequeue(self.activeChildExecutors), () => {
      const lastClose = this.closeLastSubstream;

      if (lastClose != null) {
        this.addFinalizer(() => tsplus_module_10.succeed(() => lastClose, fileName_1 + ":856:49"));
      }

      return this.finishSubexecutorWithCloseEffect(self.upstreamDone, () => lastClose, exit => self.upstreamExecutor.close(exit, fileName_1 + ":861:48"));
    }, ({
      tuple: [activeChild, rest]
    }) => {
      if (activeChild != null) {
        const parentSubexecutor = tsplus_module_29.drainChildExecutors(self.upstreamExecutor, self.lastDone, rest, self.upstreamDone, self.combineChildResults, self.combineWithChildResult, self.onPull);
        this.replaceSubexecutor(tsplus_module_29.pullFromChild(activeChild.childExecutor, parentSubexecutor, activeChild.onEmit));
        return undefined;
      }

      const {
        tuple: [emitSeparator, remainingExecutors]
      } = this.applyUpstreamPullStrategy(true, rest, self.onPull(tsplus_module_43.noUpstream(tsplus_module_47.reduce_(rest, 0, (acc, a) => a != null ? acc + 1 : acc))));
      this.replaceSubexecutor(tsplus_module_29.drainChildExecutors(self.upstreamExecutor, self.lastDone, remainingExecutors, self.upstreamDone, self.combineChildResults, self.combineWithChildResult, self.onPull));
      return tsplus_module_46.fold_(emitSeparator, () => undefined, value => {
        this.emitted = value;
        return tsplus_module_19.channelStateEmit;
      });
    });
  }

  handleSubexecFailure(childExecutor, parentSubexecutor, cause) {
    return this.finishSubexecutorWithCloseEffect(tsplus_module_35.failCause(cause), exit => parentSubexecutor.close(exit, fileName_1 + ":922:40"), exit => childExecutor.close(exit, fileName_1 + ":923:36"));
  }

  finishWithDoneValue(childExecutor, parentSubexecutor, doneValue) {
    void 0;

    switch (parentSubexecutor._tag) {
      case "PullFromUpstream":
        {
          const modifiedParent = tsplus_module_29.pullFromUpstream(parentSubexecutor.upstreamExecutor, parentSubexecutor.createChild, parentSubexecutor.lastDone != null ? parentSubexecutor.combineChildResults(parentSubexecutor.lastDone, doneValue) : doneValue, parentSubexecutor.activeChildExecutors, parentSubexecutor.combineChildResults, parentSubexecutor.combineWithChildResult, parentSubexecutor.onPull, parentSubexecutor.onEmit);
          this.closeLastSubstream = childExecutor.close(tsplus_module_33.succeed(doneValue), fileName_1 + ":950:54");
          this.replaceSubexecutor(modifiedParent);
          break;
        }

      case "DrainChildExecutors":
        {
          const modifiedParent = tsplus_module_29.drainChildExecutors(parentSubexecutor.upstreamExecutor, parentSubexecutor.lastDone != null ? parentSubexecutor.combineChildResults(parentSubexecutor.lastDone, doneValue) : doneValue, parentSubexecutor.activeChildExecutors, parentSubexecutor.upstreamDone, parentSubexecutor.combineChildResults, parentSubexecutor.combineWithChildResult, parentSubexecutor.onPull);
          this.closeLastSubstream = childExecutor.close(tsplus_module_33.succeed(doneValue), fileName_1 + ":969:54");
          this.replaceSubexecutor(modifiedParent);
          break;
        }

      default:
        {
          break;
        }
    }
  }

  pullFromChild(childExecutor, parentSubexecutor, onEmitted, self) {
    return tsplus_module_19.channelStateRead(childExecutor, tsplus_module_26.identity, emitted => {
      const decision = onEmitted(emitted);

      switch (decision._tag) {
        case "Yield":
          {
            const modifiedParent = parentSubexecutor.enqueuePullFromChild(self);
            this.replaceSubexecutor(modifiedParent);
            break;
          }

        case "Close":
          {
            this.finishWithDoneValue(childExecutor, parentSubexecutor, decision.value);
            break;
          }

        case "Continue":
          {
            break;
          }
      }

      this.activeSubexecutor = tsplus_module_29.emit(emitted, this.activeSubexecutor);
      return undefined;
    }, exit => {
      switch (exit._tag) {
        case "Failure":
          {
            const result = this.handleSubexecFailure(childExecutor, parentSubexecutor, exit.cause);
            return result != null ? tsplus_module_19.effectOrUndefinedIgnored(result, fileName_1 + ":1015:68") : undefined;
          }

        case "Success":
          {
            this.finishWithDoneValue(childExecutor, parentSubexecutor, exit.value);
            return undefined;
          }
      }
    });
  }

}
export function readUpstream(r, cont, __tsplusTrace) {
  const readStack = new tsplus_module_48.Stack(r);
  return read(readStack, cont, __tsplusTrace);
}

function read(readStack, cont, __tsplusTrace) {
  const current = readStack.value;
  let newReadStack = readStack.previous;
  const state = current.upstream.run();
  void 0;

  switch (state._tag) {
    case "Emit":
      {
        const emitEffect = current.onEmit(current.upstream.getEmit());

        if (newReadStack == null) {
          if (emitEffect == null) {
            return tsplus_module_23.suspendSucceed(() => cont(), __tsplusTrace);
          }

          return tsplus_module_7.zipRight_(emitEffect, () => cont(), __tsplusTrace);
        }

        if (emitEffect == null) {
          return tsplus_module_23.suspendSucceed(() => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
        }

        return tsplus_module_7.zipRight_(emitEffect, () => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
      }

    case "Done":
      {
        const doneEffect = current.onDone(current.upstream.getDone());

        if (newReadStack == null) {
          if (doneEffect == null) {
            return tsplus_module_23.suspendSucceed(() => cont(), __tsplusTrace);
          }

          return tsplus_module_7.zipRight_(doneEffect, () => cont(), __tsplusTrace);
        }

        if (doneEffect == null) {
          return tsplus_module_23.suspendSucceed(() => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
        }

        return tsplus_module_7.zipRight_(doneEffect, () => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
      }

    case "Effect":
      {
        newReadStack = new tsplus_module_48.Stack(current, newReadStack);
        return tsplus_module_7.zipRight_(tsplus_module_22.catchAllCause_(current.onEffect(state.effect), cause => tsplus_module_23.suspendSucceed(() => {
          const doneEffect = current.onDone(tsplus_module_35.failCause(cause));
          return doneEffect == null ? tsplus_module_2.unit : doneEffect;
        }, __tsplusTrace), __tsplusTrace), () => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
      }

    case "Read":
      {
        newReadStack = new tsplus_module_48.Stack(current, newReadStack);
        newReadStack = new tsplus_module_48.Stack(state, newReadStack);
        return tsplus_module_23.suspendSucceed(() => read(newReadStack, cont, __tsplusTrace), __tsplusTrace);
      }
  }
}
//# sourceMappingURL=ChannelExecutor.mjs.map