Skip to content

Commit

Permalink
fix Do expressions not always being reusable
Browse files Browse the repository at this point in the history
  • Loading branch information
cevr committed Jun 29, 2023
1 parent eb6b1fe commit 0ded560
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/quick-tables-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftld": patch
---

fix Do expressions not being always reusable
21 changes: 20 additions & 1 deletion lib/src/do.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ describe("Do", () => {
Task.from(async () => 2),
() => new OtherError()
);
return Result.from(a + b, () => new AnotherError());
return Result.from(
() => a + b,
() => new AnotherError()
);
});

const res2 = Do(function* ($) {
Expand All @@ -350,4 +353,20 @@ describe("Do", () => {

expect(await res1.run()).toEqual(Result.Ok(3));
});

it("should able to reuse a Do expression", async () => {
const res = Do(function* ($) {
const a = yield* $(Task.from(async () => 1));
const b = yield* $(Option.from(2));
return a + b;
});

let result = res.run();
expect(result).toBeInstanceOf(Promise);
expect(await result).toEqual(Result.Ok(3));

let result2 = res.run();
expect(result2).toBeInstanceOf(Promise);
expect(await result2).toEqual(Result.Ok(3));
});
});
27 changes: 16 additions & 11 deletions lib/src/do.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,27 @@ export type Unwrapper = <A, E = UnwrapError<A>>(
onErr?: (e: KnownError<A>) => E
) => UnwrapGen<A, E>;

const run = (
iterator: Generator<any, any, any>,
state: IteratorResult<UnwrapGen<unknown>>
): any => {
if (state.done) {
return toTask(state.value);
}

return toTask(state.value).flatMap((x) => run(iterator, iterator.next(x)));
};

export function Do<T, Gen extends UnwrapGen<unknown, unknown>>(
f: ($: Unwrapper) => Generator<Gen, T, any>
): ComputeTask<Gen[], T> {
const iterator = f((x, e) => new UnwrapGen(x, e));

const run = (state: IteratorResult<UnwrapGen<unknown>>): any => {
if (state.done) {
return toTask(state.value);
}
// @ts-expect-error
return Task.from(() => {
const iterator = f((x, e) => new UnwrapGen(x, e));

// @ts-expect-error
return toTask(state.value).flatMap((x) => run(iterator.next(x)));
};

// @ts-expect-error
return Task.from(() => run(iterator.next()));
return run(iterator, iterator.next());
});
}

const toTask = (maybeGen: unknown): Task<unknown, unknown> => {
Expand Down
21 changes: 21 additions & 0 deletions lib/src/task.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1897,4 +1897,25 @@ describe.concurrent("Task", () => {
]);
});
});

it("should be able to rerun itself infinitely", async () => {
const fn = vi.fn();
const task = Task.from(async () => {
fn();
return 1;
});
const tasks = Array.from({ length: 10 }, () => task);
const res = await Task.parallel(tasks).run();
expect(fn).toBeCalledTimes(10);
expect(res).toEqual(Result.Ok([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]));
});

it("should be reusable", async () => {
const task = Task.from(async () => 1);

const res = task.run();
expect(res).toBeInstanceOf(Promise);
await res;
expect(task.run()).toBeInstanceOf(Promise);
});
});

0 comments on commit 0ded560

Please sign in to comment.