UNPKG

@effect-ts/system

Version:

Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.

664 lines (565 loc) 21.1 kB
// ets_tracing: off import "../../../../Operator/index.mjs"; import * as L from "../../../../Collections/Immutable/List/index.mjs"; import * as T from "../../../../Effect/index.mjs"; import * as Either from "../../../../Either/index.mjs"; import * as Exit from "../../../../Exit/index.mjs"; import * as F from "../../../../Fiber/index.mjs"; import * as O from "../../../../Option/index.mjs"; import * as P from "./primitives.mjs"; export const FromKAndTypeId = /*#__PURE__*/Symbol(); export class FromKAnd { constructor(fromK, rest) { this.fromK = fromK; this.rest = rest; this._typeId = FromKAndTypeId; } } export const InnerTypeId = /*#__PURE__*/Symbol(); export class Inner { constructor(exec, subK, lastDone, combineSubK, combineSubKAndInner) { this.exec = exec; this.subK = subK; this.lastDone = lastDone; this.combineSubK = combineSubK; this.combineSubKAndInner = combineSubKAndInner; this._typeId = InnerTypeId; } close(ex) { const fin = this.exec.close(ex); if (fin) { return T.result(fin); } } } export const ChannelStateDoneTypeId = /*#__PURE__*/Symbol(); export class ChannelStateDone { constructor() { this._typeId = ChannelStateDoneTypeId; } } export const ChannelStateEmitTypeId = /*#__PURE__*/Symbol(); export class ChannelStateEmit { constructor() { this._typeId = ChannelStateEmitTypeId; } } export const ChannelStateEffectTypeId = /*#__PURE__*/Symbol(); export class ChannelStateEffect { constructor(effect) { this.effect = effect; this._typeId = ChannelStateEffectTypeId; } } const _ChannelStateDone = /*#__PURE__*/new ChannelStateDone(); const _ChannelStateEmit = /*#__PURE__*/new ChannelStateEmit(); export function channelStateEffect(state) { if ((state === null || state === void 0 ? void 0 : state._typeId) === ChannelStateEffectTypeId) { return state.effect; } return T.unit; } export function channelStateUnroll(runStep) { const step = runStep(); switch (step._typeId) { case ChannelStateEffectTypeId: { return T.chain_(step.effect, () => channelStateUnroll(runStep)); } case ChannelStateDoneTypeId: { return T.succeed(Either.right(_ChannelStateDone)); } case ChannelStateEmitTypeId: { return T.succeed(Either.left(_ChannelStateEmit)); } } } export function maybeCloseBoth(l, r) { if (l && r) { return T.zipWith_(T.result(l), T.result(r), (a, b) => Exit.zipRight_(a, b)); } else if (l) { return T.result(l); } else if (r) { return T.result(r); } } const endUnit = /*#__PURE__*/new P.Done(() => void 0); export class ChannelExecutor { constructor(initialChannel, providedEnv, executeCloseLastSubstream) { this.providedEnv = providedEnv; this.executeCloseLastSubstream = executeCloseLastSubstream; this.doneStack = L.empty(); this.currentChannel = initialChannel(); } restorePipe(exit, prev) { const currInput = this.input; this.input = prev; return currInput === null || currInput === void 0 ? void 0 : currInput.close(exit); } unwindAllFinalizers(acc, conts, exit) { while (!L.isEmpty(conts)) { const head = L.unsafeFirst(conts); ; if (head._typeId === P.ContinuationKTypeId) { conts = L.tail(conts); } else { return T.chain_(T.result(head.finalizer(exit)), finExit => this.unwindAllFinalizers(Exit.zipRight_(acc, finExit), L.tail(conts), exit)); } } return T.done(acc); } popAllFinalizers(exit) { const effect = T.result(this.unwindAllFinalizers(Exit.unit, this.doneStack, exit)); this.doneStack = L.empty(); this.storeInProgressFinalizer(effect); return effect; } popNextFinalizersGo(stack, builder) { while (!L.isEmpty(stack)) { const head = L.unsafeFirst(stack); ; if (head._typeId === P.ContinuationKTypeId) { return stack; } L.push_(builder, head); stack = L.tail(stack); } return L.empty(); } popNextFinalizers() { const builder = L.emptyPushable(); this.doneStack = this.popNextFinalizersGo(this.doneStack, builder); return builder; } storeInProgressFinalizer(effect) { this.inProgressFinalizer = effect; } clearInProgressFinalizer() { this.inProgressFinalizer = undefined; } ifNotNull(effect) { return effect ? effect : T.succeed(Exit.unit); } close(ex) { const runInProgressFinalizer = this.inProgressFinalizer ? T.ensuring_(this.inProgressFinalizer, T.succeedWith(() => this.clearInProgressFinalizer())) : undefined; let closeSubexecutors; if (this.subexecutorStack) { if (this.subexecutorStack._typeId === InnerTypeId) { closeSubexecutors = this.subexecutorStack.close(ex); } else { const fin1 = this.subexecutorStack.fromK.close(ex); const fin2 = this.subexecutorStack.rest.close(ex); if (fin1 && fin2) { closeSubexecutors = T.zipWith_(T.result(fin1), T.result(fin2), (a, b) => Exit.zipRight_(a, b)); } else if (fin1) { closeSubexecutors = T.result(fin1); } else if (fin2) { closeSubexecutors = T.result(fin2); } } } let closeSelf; const selfFinalizers = this.popAllFinalizers(ex); if (selfFinalizers) { closeSelf = T.ensuring_(selfFinalizers, T.succeedWith(() => this.clearInProgressFinalizer())); } if (closeSubexecutors || runInProgressFinalizer || closeSelf) { return T.uninterruptible(T.map_(T.tuple(this.ifNotNull(closeSubexecutors), this.ifNotNull(runInProgressFinalizer), this.ifNotNull(closeSelf)), ({ tuple: [a, b, c] }) => Exit.zipRight_(a, Exit.zipRight_(b, c)))); } } getDone() { return this.done; } getEmit() { return this.emitted; } cancelWith(exit) { this.cancelled = exit; } run() { let result = undefined; while (!result) { if (this.cancelled) { result = this.processCancellation(); } else if (this.subexecutorStack) { result = this.drainSubexecutor(); } else { if (!this.currentChannel) { result = _ChannelStateDone; } else { ; const currentChannel = this.currentChannel; switch (currentChannel._typeId) { case P.BridgeTypeId: { this.currentChannel = currentChannel.channel; if (this.input) { const inputExecutor = this.input; this.input = undefined; const drainer = T.zipRight_(currentChannel.input.awaitRead, T.suspend(() => { const state = inputExecutor.run(); switch (state._typeId) { case ChannelStateEmitTypeId: { return T.chain_(currentChannel.input.emit(inputExecutor.getEmit()), () => drainer); } case ChannelStateEffectTypeId: { return T.foldCauseM_(state.effect, cause => currentChannel.input.error(cause), () => drainer); } case ChannelStateDoneTypeId: { const done = inputExecutor.getDone(); return done._tag === "Success" ? currentChannel.input.done(done.value) : currentChannel.input.error(done.cause); } } })); result = new ChannelStateEffect(T.chain_(T.fork(drainer), fiber => T.succeedWith(() => { this.addFinalizer(new P.ContinuationFinalizer(exit => T.chain_(F.interrupt(fiber), () => T.suspend(() => this.restorePipe(exit, inputExecutor) || T.unit)))); }))); } break; } case P.PipeToTypeId: { const previousInput = this.input; const leftExec = new ChannelExecutor(currentChannel.left, this.providedEnv, this.executeCloseLastSubstream); leftExec.input = previousInput; this.input = leftExec; this.addFinalizer(new P.ContinuationFinalizer(exit => this.restorePipe(exit, previousInput) || T.unit)); this.currentChannel = currentChannel.right(); break; } case P.ReadTypeId: { result = this.runRead(currentChannel); break; } case P.DoneTypeId: { result = this.doneSucceed(currentChannel.terminal()); break; } case P.HaltTypeId: { result = this.doneHalt(currentChannel.error()); break; } case P.EffectTypeId: { const peffect = typeof this.providedEnv !== "undefined" ? T.provideAll_(currentChannel.effect, this.providedEnv) : currentChannel.effect; result = new ChannelStateEffect(T.foldCauseM_(peffect, cause => { const res = this.doneHalt(cause); if ((res === null || res === void 0 ? void 0 : res._typeId) === ChannelStateEffectTypeId) { return res.effect; } else { return T.unit; } }, z => { const res = this.doneSucceed(z); if ((res === null || res === void 0 ? void 0 : res._typeId) === ChannelStateEffectTypeId) { return res.effect; } else { return T.unit; } })); break; } case P.EmitTypeId: { this.emitted = currentChannel.out(); this.currentChannel = endUnit; result = _ChannelStateEmit; break; } case P.EnsuringTypeId: { this.addFinalizer(new P.ContinuationFinalizer(e => currentChannel.finalizer(e))); this.currentChannel = currentChannel.channel; break; } case P.ConcatAllTypeId: { const innerExecuteLastClose = f => T.succeedWith(() => { const prevLastClose = this.closeLastSubstream ? this.closeLastSubstream : T.unit; this.closeLastSubstream = T.zipRight_(prevLastClose, f); }); const exec = new ChannelExecutor(() => currentChannel.value, this.providedEnv, innerExecuteLastClose); exec.input = this.input; this.subexecutorStack = new Inner(exec, currentChannel.k, undefined, currentChannel.combineInners, currentChannel.combineAll); this.closeLastSubstream = undefined; this.currentChannel = undefined; break; } case P.FoldTypeId: { this.doneStack = L.prepend_(this.doneStack, currentChannel.k); this.currentChannel = currentChannel.value; break; } case P.BracketOutTypeId: { result = this.runBracketOut(currentChannel); break; } case P.ProvideTypeId: { const previousEnv = this.providedEnv; this.providedEnv = currentChannel.env; this.currentChannel = currentChannel.channel; this.addFinalizer(new P.ContinuationFinalizer(() => T.succeedWith(() => { this.providedEnv = previousEnv; }))); break; } case P.EffectTotalTypeId: { result = this.doneSucceed(currentChannel.effect()); break; } case P.EffectSuspendTotalTypeId: { this.currentChannel = currentChannel.effect(); break; } } } } } return result; } runReadGo(state, read, input) { switch (state._typeId) { case ChannelStateEmitTypeId: { return T.succeedWith(() => { this.currentChannel = read.more(input.getEmit()); }); } case ChannelStateDoneTypeId: { return T.succeedWith(() => { this.currentChannel = read.done.onExit(input.getDone()); }); } case ChannelStateEffectTypeId: { return T.foldCauseM_(state.effect, cause => T.succeedWith(() => { this.currentChannel = read.done.onHalt(cause); }), () => this.runReadGo(input.run(), read, input)); } } } runRead(read) { if (this.input) { const input = this.input; const state = input.run(); switch (state._typeId) { case ChannelStateEmitTypeId: { this.currentChannel = read.more(input.getEmit()); return; } case ChannelStateDoneTypeId: { this.currentChannel = read.done.onExit(input.getDone()); return; } case ChannelStateEffectTypeId: { return new ChannelStateEffect(T.foldCauseM_(state.effect, cause => T.succeedWith(() => { this.currentChannel = read.done.onHalt(cause); }), () => this.runReadGo(input.run(), read, input))); } } } else { this.currentChannel = read.more(void 0); } } runBracketOut(bracketOut) { return new ChannelStateEffect(T.uninterruptibleMask(mask => T.foldCauseM_(mask.restore(bracketOut.acquire), cause => T.succeedWith(() => { this.currentChannel = new P.Halt(() => cause); }), out => T.succeedWith(() => { this.addFinalizer(new P.ContinuationFinalizer(e => bracketOut.finalizer(out, e))); this.currentChannel = new P.Emit(() => out); })))); } addFinalizer(f) { this.doneStack = L.prepend_(this.doneStack, f); } drainSubexecutor() { const subexecutorStack = this.subexecutorStack; if (subexecutorStack._typeId === InnerTypeId) { return this.drainInnerSubExecutor(subexecutorStack); } else { return this.drainFromKAndSubexecutor(subexecutorStack.fromK, subexecutorStack.rest); } } handleSubexecFailure(exec, rest, self, cause) { return self.finishSubexecutorWithCloseEffect(Exit.halt(cause), _ => rest.exec.close(_), _ => exec.close(_)); } drainFromKAndSubexecutor(exec, rest) { const run = exec.run(); switch (run._typeId) { case ChannelStateEffectTypeId: { return new ChannelStateEffect(T.catchAllCause_(run.effect, cause => channelStateEffect(this.handleSubexecFailure(exec, rest, this, cause)))); } case ChannelStateEmitTypeId: { this.emitted = exec.getEmit(); return _ChannelStateEmit; } case ChannelStateDoneTypeId: { const done = exec.getDone(); switch (done._tag) { case "Failure": { return this.handleSubexecFailure(exec, rest, this, done.cause); } case "Success": { const modifiedRest = new Inner(rest.exec, rest.subK, rest.lastDone ? rest.combineSubK(rest.lastDone, done.value) : done.value, rest.combineSubK, rest.combineSubKAndInner); this.closeLastSubstream = exec.close(done); this.replaceSubexecutor(modifiedRest); return undefined; } } } } } replaceSubexecutor(nextSubExec) { this.currentChannel = undefined; this.subexecutorStack = nextSubExec; } finishSubexecutorWithCloseEffect(subexecDone, ...closeFns) { this.addFinalizer(new P.ContinuationFinalizer(_ => T.forEachUnit_(closeFns, closeFn => T.chain_(T.succeedWith(() => closeFn(subexecDone)), closeEffect => { if (closeEffect) { return closeEffect; } else { return T.unit; } })))); const state = Exit.fold_(subexecDone, e => this.doneHalt(e), a => this.doneSucceed(a)); this.subexecutorStack = undefined; return state; } doneSucceed(z) { if (L.isEmpty(this.doneStack)) { this.done = Exit.succeed(z); this.currentChannel = undefined; return _ChannelStateDone; } const head = L.unsafeFirst(this.doneStack); ; if (head._typeId === P.ContinuationKTypeId) { this.doneStack = L.tail(this.doneStack); this.currentChannel = head.onSuccess(z); return; } else { const finalizers = this.popNextFinalizers(); if (L.isEmpty(this.doneStack)) { this.doneStack = finalizers; this.done = Exit.succeed(z); this.currentChannel = undefined; return _ChannelStateDone; } else { const finalizerEffect = this.runFinalizers(L.map_(finalizers, _ => _.finalizer), Exit.succeed(z)); this.storeInProgressFinalizer(finalizerEffect); return new ChannelStateEffect(T.chain_(T.uninterruptible(T.ensuring_(finalizerEffect, T.succeedWith(() => { this.clearInProgressFinalizer(); }))), () => T.succeedWith(() => this.doneSucceed(z)))); } } } runFinalizers(finalizers, ex) { if (L.isEmpty(finalizers)) { return T.succeed(Exit.unit); } return T.map_(T.forEach_(finalizers, cont => T.result(cont(ex))), results => O.getOrElse_(Exit.collectAll(...results), () => Exit.unit)); } doneHalt(cause) { if (L.isEmpty(this.doneStack)) { this.done = Exit.halt(cause); this.currentChannel = undefined; return _ChannelStateDone; } const head = L.unsafeFirst(this.doneStack); ; if (head._typeId === P.ContinuationKTypeId) { this.doneStack = L.tail(this.doneStack); this.currentChannel = head.onHalt(cause); return; } else { const finalizers = this.popNextFinalizers(); if (L.isEmpty(this.doneStack)) { this.doneStack = finalizers; this.done = Exit.halt(cause); this.currentChannel = undefined; return _ChannelStateDone; } else { const finalizerEffect = this.runFinalizers(L.map_(finalizers, _ => _.finalizer), Exit.halt(cause)); this.storeInProgressFinalizer(finalizerEffect); return new ChannelStateEffect(T.chain_(T.uninterruptible(T.ensuring_(finalizerEffect, T.succeedWith(() => { this.clearInProgressFinalizer(); }))), () => T.succeedWith(() => this.doneHalt(cause)))); } } } drainInnerSubExecutor(inner) { const run = inner.exec.run(); switch (run._typeId) { case ChannelStateEmitTypeId: { if (this.closeLastSubstream) { const closeLast = this.closeLastSubstream; this.closeLastSubstream = undefined; return new ChannelStateEffect(T.map_(this.executeCloseLastSubstream(closeLast), _ => { const fromK = new ChannelExecutor(() => inner.subK(inner.exec.getEmit()), this.providedEnv, this.executeCloseLastSubstream); fromK.input = this.input; this.subexecutorStack = new FromKAnd(fromK, inner); })); } else { const fromK = new ChannelExecutor(() => inner.subK(inner.exec.getEmit()), this.providedEnv, this.executeCloseLastSubstream); fromK.input = this.input; this.subexecutorStack = new FromKAnd(fromK, inner); return undefined; } } case ChannelStateDoneTypeId: { const lastClose = this.closeLastSubstream; const done = inner.exec.getDone(); switch (done._tag) { case "Failure": { return this.finishSubexecutorWithCloseEffect(done, () => lastClose, _ => inner.exec.close(_)); } case "Success": { const doneValue = Exit.succeed(inner.combineSubKAndInner(inner.lastDone, done.value)); return this.finishSubexecutorWithCloseEffect(doneValue, () => lastClose, _ => inner.exec.close(_)); } } } case ChannelStateEffectTypeId: { const closeLast = this.closeLastSubstream ? this.closeLastSubstream : T.unit; this.closeLastSubstream = undefined; return new ChannelStateEffect(T.zipRight_(this.executeCloseLastSubstream(closeLast), T.catchAllCause_(run.effect, cause => channelStateEffect(this.finishSubexecutorWithCloseEffect(Exit.halt(cause), _ => inner.exec.close(_), _ => inner.exec.close(_)))))); } } } processCancellation() { this.currentChannel = undefined; this.done = this.cancelled; this.cancelled = undefined; return _ChannelStateDone; } } //# sourceMappingURL=executor.mjs.map