veffect
Version:
powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha
546 lines (545 loc) • 20 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.zipWith = exports.zipRight = exports.zipLeft = exports.zip = exports.withSTMRuntime = exports.unsafeAtomically = exports.sync = exports.succeed = exports.retry = exports.orTry = exports.matchSTM = exports.mapInputContext = exports.map = exports.isSTM = exports.interruptAs = exports.interrupt = exports.flatMap = exports.failSync = exports.fail = exports.ensuring = exports.effect = exports.dieSync = exports.dieMessage = exports.die = exports.contextWithSTM = exports.contextWith = exports.context = exports.commit = exports.catchAll = exports.STMTypeId = exports.STMDriver = void 0;
var Cause = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Cause.js"));
var Context = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Context.js"));
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Effect.js"));
var Either = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Either.js"));
var Equal = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Equal.js"));
var Exit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Exit.js"));
var FiberRef = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../FiberRef.js"));
var _Function = /*#__PURE__*/require("../../Function.js");
var Hash = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../Hash.js"));
var _Pipeable = /*#__PURE__*/require("../../Pipeable.js");
var _Predicate = /*#__PURE__*/require("../../Predicate.js");
var _Stream = /*#__PURE__*/require("../../Stream.js");
var _coreStream = /*#__PURE__*/require("../core-stream.js");
var _core = /*#__PURE__*/require("../core.js");
var _effectable = /*#__PURE__*/require("../effectable.js");
var _effect = /*#__PURE__*/require("../opCodes/effect.js");
var _sink = /*#__PURE__*/require("../sink.js");
var OpCodes = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./opCodes/stm.js"));
var TExitOpCodes = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./opCodes/tExit.js"));
var TryCommitOpCodes = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./opCodes/tryCommit.js"));
var Journal = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./stm/journal.js"));
var STMState = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./stm/stmState.js"));
var TExit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./stm/tExit.js"));
var TryCommit = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./stm/tryCommit.js"));
var TxnId = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./stm/txnId.js"));
function _getRequireWildcardCache(e) {
if ("function" != typeof WeakMap) return null;
var r = new WeakMap(),
t = new WeakMap();
return (_getRequireWildcardCache = function (e) {
return e ? t : r;
})(e);
}
function _interopRequireWildcard(e, r) {
if (!r && e && e.__esModule) return e;
if (null === e || "object" != typeof e && "function" != typeof e) return {
default: e
};
var t = _getRequireWildcardCache(r);
if (t && t.has(e)) return t.get(e);
var n = {
__proto__: null
},
a = Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];
}
return n.default = e, t && t.set(e, n), n;
}
/** @internal */
const STMSymbolKey = "effect/STM";
/** @internal */
const STMTypeId = exports.STMTypeId = /*#__PURE__*/Symbol.for(STMSymbolKey);
const stmVariance = {
/* c8 ignore next */
_R: _ => _,
/* c8 ignore next */
_E: _ => _,
/* c8 ignore next */
_A: _ => _
};
/** @internal */
class STMPrimitive {
effect_instruction_i0;
_tag = _effect.OP_COMMIT;
_op = _effect.OP_COMMIT;
effect_instruction_i1 = undefined;
effect_instruction_i2 = undefined;
[Effect.EffectTypeId];
[_Stream.StreamTypeId];
[_sink.SinkTypeId];
[_coreStream.ChannelTypeId];
get [STMTypeId]() {
return stmVariance;
}
constructor(effect_instruction_i0) {
this.effect_instruction_i0 = effect_instruction_i0;
this[Effect.EffectTypeId] = _effectable.effectVariance;
this[_Stream.StreamTypeId] = stmVariance;
this[_sink.SinkTypeId] = stmVariance;
this[_coreStream.ChannelTypeId] = stmVariance;
}
[Equal.symbol](that) {
return this === that;
}
[Hash.symbol]() {
return Hash.cached(this, Hash.random(this));
}
commit() {
return unsafeAtomically(this, _Function.constVoid, _Function.constVoid);
}
pipe() {
return (0, _Pipeable.pipeArguments)(this, arguments);
}
}
/** @internal */
const isSTM = u => (0, _Predicate.hasProperty)(u, STMTypeId);
/** @internal */
exports.isSTM = isSTM;
const commit = self => unsafeAtomically(self, _Function.constVoid, _Function.constVoid);
/** @internal */
exports.commit = commit;
const unsafeAtomically = (self, onDone, onInterrupt) => (0, _core.withFiberRuntime)(state => {
const fiberId = state.id();
const env = state.getFiberRef(FiberRef.currentContext);
const scheduler = state.getFiberRef(FiberRef.currentScheduler);
const priority = state.getFiberRef(FiberRef.currentSchedulingPriority);
const commitResult = tryCommitSync(fiberId, self, env, scheduler, priority);
switch (commitResult._tag) {
case TryCommitOpCodes.OP_DONE:
{
onDone(commitResult.exit);
return commitResult.exit;
}
case TryCommitOpCodes.OP_SUSPEND:
{
const txnId = TxnId.make();
const state = {
value: STMState.running
};
const effect = Effect.async(k => tryCommitAsync(fiberId, self, txnId, state, env, scheduler, priority, k));
return Effect.uninterruptibleMask(restore => (0, _Function.pipe)(restore(effect), Effect.catchAllCause(cause => {
let currentState = state.value;
if (STMState.isRunning(currentState)) {
state.value = STMState.interrupted;
}
currentState = state.value;
if (STMState.isDone(currentState)) {
onDone(currentState.exit);
return currentState.exit;
}
onInterrupt();
return Effect.failCause(cause);
})));
}
}
});
/** @internal */
exports.unsafeAtomically = unsafeAtomically;
const tryCommit = (fiberId, stm, state, env, scheduler, priority) => {
const journal = new Map();
const tExit = new STMDriver(stm, journal, fiberId, env).run();
const analysis = Journal.analyzeJournal(journal);
if (analysis === Journal.JournalAnalysisReadWrite) {
Journal.commitJournal(journal);
} else if (analysis === Journal.JournalAnalysisInvalid) {
throw new Error("BUG: STM.TryCommit.tryCommit - please report an issue at https://github.com/Effect-TS/effect/issues");
}
switch (tExit._tag) {
case TExitOpCodes.OP_SUCCEED:
{
state.value = STMState.fromTExit(tExit);
return completeTodos(Exit.succeed(tExit.value), journal, scheduler, priority);
}
case TExitOpCodes.OP_FAIL:
{
state.value = STMState.fromTExit(tExit);
const cause = Cause.fail(tExit.error);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_DIE:
{
state.value = STMState.fromTExit(tExit);
const cause = Cause.die(tExit.defect);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_INTERRUPT:
{
state.value = STMState.fromTExit(tExit);
const cause = Cause.interrupt(fiberId);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_RETRY:
{
return TryCommit.suspend(journal);
}
}
};
/** @internal */
const tryCommitSync = (fiberId, stm, env, scheduler, priority) => {
const journal = new Map();
const tExit = new STMDriver(stm, journal, fiberId, env).run();
const analysis = Journal.analyzeJournal(journal);
if (analysis === Journal.JournalAnalysisReadWrite && TExit.isSuccess(tExit)) {
Journal.commitJournal(journal);
} else if (analysis === Journal.JournalAnalysisInvalid) {
throw new Error("BUG: STM.TryCommit.tryCommitSync - please report an issue at https://github.com/Effect-TS/effect/issues");
}
switch (tExit._tag) {
case TExitOpCodes.OP_SUCCEED:
{
return completeTodos(Exit.succeed(tExit.value), journal, scheduler, priority);
}
case TExitOpCodes.OP_FAIL:
{
const cause = Cause.fail(tExit.error);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_DIE:
{
const cause = Cause.die(tExit.defect);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_INTERRUPT:
{
const cause = Cause.interrupt(fiberId);
return completeTodos(Exit.failCause(cause), journal, scheduler, priority);
}
case TExitOpCodes.OP_RETRY:
{
return TryCommit.suspend(journal);
}
}
};
/** @internal */
const tryCommitAsync = (fiberId, self, txnId, state, context, scheduler, priority, k) => {
if (STMState.isRunning(state.value)) {
const result = tryCommit(fiberId, self, state, context, scheduler, priority);
switch (result._tag) {
case TryCommitOpCodes.OP_DONE:
{
completeTryCommit(result.exit, k);
break;
}
case TryCommitOpCodes.OP_SUSPEND:
{
Journal.addTodo(txnId, result.journal, () => tryCommitAsync(fiberId, self, txnId, state, context, scheduler, priority, k));
break;
}
}
}
};
/** @internal */
const completeTodos = (exit, journal, scheduler, priority) => {
const todos = Journal.collectTodos(journal);
if (todos.size > 0) {
scheduler.scheduleTask(() => Journal.execTodos(todos), priority);
}
return TryCommit.done(exit);
};
/** @internal */
const completeTryCommit = (exit, k) => {
k(exit);
};
/** @internal */
const context = () => effect((_, __, env) => env);
/** @internal */
exports.context = context;
const contextWith = f => map(context(), f);
/** @internal */
exports.contextWith = contextWith;
const contextWithSTM = f => flatMap(context(), f);
/** @internal */
exports.contextWithSTM = contextWithSTM;
class STMDriver {
self;
journal;
fiberId;
contStack = [];
env;
constructor(self, journal, fiberId, r0) {
this.self = self;
this.journal = journal;
this.fiberId = fiberId;
this.env = r0;
}
getEnv() {
return this.env;
}
pushStack(cont) {
this.contStack.push(cont);
}
popStack() {
return this.contStack.pop();
}
nextSuccess() {
let current = this.popStack();
while (current !== undefined && current.effect_instruction_i0 !== OpCodes.OP_ON_SUCCESS) {
current = this.popStack();
}
return current;
}
nextFailure() {
let current = this.popStack();
while (current !== undefined && current.effect_instruction_i0 !== OpCodes.OP_ON_FAILURE) {
current = this.popStack();
}
return current;
}
nextRetry() {
let current = this.popStack();
while (current !== undefined && current.effect_instruction_i0 !== OpCodes.OP_ON_RETRY) {
current = this.popStack();
}
return current;
}
run() {
let curr = this.self;
let exit = undefined;
while (exit === undefined && curr !== undefined) {
try {
const current = curr;
if (current) {
switch (current._tag) {
case "Tag":
{
curr = effect((_, __, env) => Context.unsafeGet(env, current));
break;
}
case "Left":
{
curr = fail(current.left);
break;
}
case "None":
{
curr = fail(new Cause.NoSuchElementException());
break;
}
case "Right":
{
curr = succeed(current.right);
break;
}
case "Some":
{
curr = succeed(current.value);
break;
}
case "Commit":
{
switch (current.effect_instruction_i0) {
case OpCodes.OP_DIE:
{
exit = TExit.die(current.effect_instruction_i1());
break;
}
case OpCodes.OP_FAIL:
{
const cont = this.nextFailure();
if (cont === undefined) {
exit = TExit.fail(current.effect_instruction_i1());
} else {
curr = cont.effect_instruction_i2(current.effect_instruction_i1());
}
break;
}
case OpCodes.OP_RETRY:
{
const cont = this.nextRetry();
if (cont === undefined) {
exit = TExit.retry;
} else {
curr = cont.effect_instruction_i2();
}
break;
}
case OpCodes.OP_INTERRUPT:
{
exit = TExit.interrupt(this.fiberId);
break;
}
case OpCodes.OP_WITH_STM_RUNTIME:
{
curr = current.effect_instruction_i1(this);
break;
}
case OpCodes.OP_ON_SUCCESS:
case OpCodes.OP_ON_FAILURE:
case OpCodes.OP_ON_RETRY:
{
this.pushStack(current);
curr = current.effect_instruction_i1;
break;
}
case OpCodes.OP_PROVIDE:
{
const env = this.env;
this.env = current.effect_instruction_i2(env);
curr = (0, _Function.pipe)(current.effect_instruction_i1, ensuring(sync(() => this.env = env)));
break;
}
case OpCodes.OP_SUCCEED:
{
const value = current.effect_instruction_i1;
const cont = this.nextSuccess();
if (cont === undefined) {
exit = TExit.succeed(value);
} else {
curr = cont.effect_instruction_i2(value);
}
break;
}
case OpCodes.OP_SYNC:
{
const value = current.effect_instruction_i1();
const cont = this.nextSuccess();
if (cont === undefined) {
exit = TExit.succeed(value);
} else {
curr = cont.effect_instruction_i2(value);
}
break;
}
}
break;
}
}
}
} catch (e) {
curr = die(e);
}
}
return exit;
}
}
/** @internal */
exports.STMDriver = STMDriver;
const catchAll = exports.catchAll = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => {
const stm = new STMPrimitive(OpCodes.OP_ON_FAILURE);
stm.effect_instruction_i1 = self;
stm.effect_instruction_i2 = f;
return stm;
});
/** @internal */
const mapInputContext = exports.mapInputContext = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => {
const stm = new STMPrimitive(OpCodes.OP_PROVIDE);
stm.effect_instruction_i1 = self;
stm.effect_instruction_i2 = f;
return stm;
});
/** @internal */
const die = defect => dieSync(() => defect);
/** @internal */
exports.die = die;
const dieMessage = message => dieSync(() => new Cause.RuntimeException(message));
/** @internal */
exports.dieMessage = dieMessage;
const dieSync = evaluate => {
const stm = new STMPrimitive(OpCodes.OP_DIE);
stm.effect_instruction_i1 = evaluate;
return stm;
};
/** @internal */
exports.dieSync = dieSync;
const effect = f => withSTMRuntime(_ => succeed(f(_.journal, _.fiberId, _.getEnv())));
/** @internal */
exports.effect = effect;
const ensuring = exports.ensuring = /*#__PURE__*/(0, _Function.dual)(2, (self, finalizer) => matchSTM(self, {
onFailure: e => zipRight(finalizer, fail(e)),
onSuccess: a => zipRight(finalizer, succeed(a))
}));
/** @internal */
const fail = error => failSync(() => error);
/** @internal */
exports.fail = fail;
const failSync = evaluate => {
const stm = new STMPrimitive(OpCodes.OP_FAIL);
stm.effect_instruction_i1 = evaluate;
return stm;
};
/** @internal */
exports.failSync = failSync;
const flatMap = exports.flatMap = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => {
const stm = new STMPrimitive(OpCodes.OP_ON_SUCCESS);
stm.effect_instruction_i1 = self;
stm.effect_instruction_i2 = f;
return stm;
});
/** @internal */
const matchSTM = exports.matchSTM = /*#__PURE__*/(0, _Function.dual)(2, (self, {
onFailure,
onSuccess
}) => (0, _Function.pipe)(self, map(Either.right), catchAll(e => (0, _Function.pipe)(onFailure(e), map(Either.left))), flatMap(either => {
switch (either._tag) {
case "Left":
{
return succeed(either.left);
}
case "Right":
{
return onSuccess(either.right);
}
}
})));
/** @internal */
const withSTMRuntime = f => {
const stm = new STMPrimitive(OpCodes.OP_WITH_STM_RUNTIME);
stm.effect_instruction_i1 = f;
return stm;
};
/** @internal */
exports.withSTMRuntime = withSTMRuntime;
const interrupt = exports.interrupt = /*#__PURE__*/withSTMRuntime(_ => {
const stm = new STMPrimitive(OpCodes.OP_INTERRUPT);
stm.effect_instruction_i1 = _.fiberId;
return stm;
});
/** @internal */
const interruptAs = fiberId => {
const stm = new STMPrimitive(OpCodes.OP_INTERRUPT);
stm.effect_instruction_i1 = fiberId;
return stm;
};
/** @internal */
exports.interruptAs = interruptAs;
const map = exports.map = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => (0, _Function.pipe)(self, flatMap(a => sync(() => f(a)))));
/** @internal */
const orTry = exports.orTry = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => {
const stm = new STMPrimitive(OpCodes.OP_ON_RETRY);
stm.effect_instruction_i1 = self;
stm.effect_instruction_i2 = that;
return stm;
});
/** @internal */
const retry = exports.retry = /*#__PURE__*/new STMPrimitive(OpCodes.OP_RETRY);
/** @internal */
const succeed = value => {
const stm = new STMPrimitive(OpCodes.OP_SUCCEED);
stm.effect_instruction_i1 = value;
return stm;
};
/** @internal */
exports.succeed = succeed;
const sync = evaluate => {
const stm = new STMPrimitive(OpCodes.OP_SYNC);
stm.effect_instruction_i1 = evaluate;
return stm;
};
/** @internal */
exports.sync = sync;
const zip = exports.zip = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => (0, _Function.pipe)(self, zipWith(that, (a, a1) => [a, a1])));
/** @internal */
const zipLeft = exports.zipLeft = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => (0, _Function.pipe)(self, flatMap(a => (0, _Function.pipe)(that, map(() => a)))));
/** @internal */
const zipRight = exports.zipRight = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => (0, _Function.pipe)(self, flatMap(() => that)));
/** @internal */
const zipWith = exports.zipWith = /*#__PURE__*/(0, _Function.dual)(3, (self, that, f) => (0, _Function.pipe)(self, flatMap(a => (0, _Function.pipe)(that, map(b => f(a, b))))));
//# sourceMappingURL=core.js.map