Skip to content

Commit

Permalink
Lift a simple function into an operation safely.
Browse files Browse the repository at this point in the history
There is the potential for a function, if it is a continuation, to
cause the scope in which it is called to be destroyed. In this
case, nothing after that function should ever be called. However,
because of the way `lift()` is currently implemented, this will not be
the case.

This unpacks the `lift()` function to be a single instruction that
immediately returns value of invoking the function. However, because
there is a `yield` point in the computation, it is an opportunity to
not continue which will happen if corresponding frame is closed.
  • Loading branch information
cowboyd committed Jan 6, 2024
1 parent 7fa2c1d commit 31e00b6
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
10 changes: 7 additions & 3 deletions lib/lift.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { shift } from "./deps.ts";
import { type Operation } from "./types.ts";

/**
Expand All @@ -20,9 +21,12 @@ export function lift<TArgs extends unknown[], TReturn>(
): LiftedFn<TArgs, TReturn> {
return (...args: TArgs) => {
return ({
[Symbol.iterator]() {
let value = fn(...args);
return { next: () => ({ done: true, value }) };
*[Symbol.iterator]() {
return yield () => {
return shift(function* (k) {
k({ ok: true, value: fn(...args) });
});
};
},
});
};
Expand Down
23 changes: 23 additions & 0 deletions test/lift.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createSignal, each, lift, run, sleep, spawn } from "../mod.ts";
import { describe, expect, it } from "./suite.ts";

describe("lift", () => {
it("safely does not continue if the call stops the operation", async () => {
let reached = false;

await run(function* () {
let signal = createSignal<void, void>();

yield* spawn(function* () {
yield* sleep(0);
yield* lift(signal.close)();

reached = true;
});

for (let _ of yield* each(signal));
});

expect(reached).toBe(false);
});
});

0 comments on commit 31e00b6

Please sign in to comment.