import * as tsplus_module_1 from "@tsplus/stdlib/data/Stack";
import * as tsplus_module_2 from "@effect/core/stm/TExit/definition";
import * as tsplus_module_3 from "@effect/core/stm/STM/definition/primitives";
import * as tsplus_module_4 from "@effect/core/stm/STM/operations/succeed";
import * as tsplus_module_5 from "@effect/core/stm/STM/operations/ensuring";
import { concreteSTM } from "@effect/core/stm/STM/definition/primitives";
export class STMDriver {
  constructor(self, journal, fiberId, r0) {
    this.self = self;
    this.journal = journal;
    this.fiberId = fiberId;
    this.yieldOpCount = 2048;
    this.envStack = new tsplus_module_1.Stack(r0);
  }

  unwindStack(error, isRetry) {
    let result = undefined;

    while (this.contStack && result == null) {
      const cont = this.contStack.value;
      this.contStack = this.contStack.previous;

      if (cont._tag === "STMOnFailure") {
        if (!isRetry) {
          result = cont.onFailure(error);
        }
      }

      if (cont._tag === "STMOnRetry") {
        if (isRetry) {
          result = cont.onRetry();
        }
      }
    }

    return result;
  }

  run() {
    let curr = this.self;
    let exit = undefined;
    let opCount = 0;

    while (exit == null && curr != null) {
      if (opCount === this.yieldOpCount) {
        let valid = true;

        for (const entry of this.journal) {
          valid = entry[1].use(_ => _.isValid());
        }

        if (!valid) {
          exit = tsplus_module_2.retry;
        } else {
          opCount = 0;
        }
      } else {
        const k = curr;
        void 0;

        switch (k._tag) {
          case "STMEffect":
            {
              try {
                const a = k.f(this.journal, this.fiberId, this.envStack.value);

                if (!this.contStack) {
                  exit = tsplus_module_2.succeed(a);
                } else {
                  const cont = this.contStack.value;
                  this.contStack = this.contStack.previous;
                  curr = cont.apply(a);
                }
              } catch (e) {
                if (tsplus_module_3.isRetryException(e)) {
                  curr = this.unwindStack(undefined, true);

                  if (!curr) {
                    exit = tsplus_module_2.retry;
                  }
                } else if (tsplus_module_3.isFailException(e)) {
                  curr = this.unwindStack(e.e, false);

                  if (!curr) {
                    exit = tsplus_module_2.fail(e.e);
                  }
                } else if (tsplus_module_3.isDieException(e)) {
                  curr = this.unwindStack(e.e, false);

                  if (!curr) {
                    exit = tsplus_module_2.die(e.e);
                  }
                } else if (tsplus_module_3.isInterruptException(e)) {
                  exit = tsplus_module_2.interrupt(e.fiberId);
                } else {
                  throw e;
                }
              }

              break;
            }

          case "STMOnSuccess":
            {
              this.contStack = new tsplus_module_1.Stack(k, this.contStack);
              curr = k.stm;
              break;
            }

          case "STMOnFailure":
            {
              this.contStack = new tsplus_module_1.Stack(k, this.contStack);
              curr = k.stm;
              break;
            }

          case "STMOnRetry":
            {
              this.contStack = new tsplus_module_1.Stack(k, this.contStack);
              curr = k.stm;
              break;
            }

          case "STMProvide":
            {
              this.envStack = new tsplus_module_1.Stack(k.f(this.envStack.value), this.envStack);
              curr = tsplus_module_5.ensuring_(k.stm, tsplus_module_4.succeed(() => {
                this.envStack = this.envStack.previous;
              }));
              break;
            }

          case "STMSucceedNow":
            {
              const a = k.a;

              if (!this.contStack) {
                exit = tsplus_module_2.succeed(a);
              } else {
                const cont = this.contStack.value;
                this.contStack = this.contStack.previous;
                curr = cont.apply(a);
              }

              break;
            }

          case "STMSucceed":
            {
              const a = k.a();

              if (!this.contStack) {
                exit = tsplus_module_2.succeed(a);
              } else {
                const cont = this.contStack.value;
                this.contStack = this.contStack.previous;
                curr = cont.apply(a);
              }

              break;
            }
        }

        opCount = opCount + 1;
      }
    }

    return exit;
  }

}
//# sourceMappingURL=STMDriver.mjs.map