Skip to content

Commit

Permalink
Merge pull request #918 from thefrontside/do-effect
Browse files Browse the repository at this point in the history
✨Introduce Do() operation
  • Loading branch information
cowboyd authored Nov 5, 2024
2 parents f2097a0 + 0541c33 commit c8a5eec
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 15 deletions.
22 changes: 7 additions & 15 deletions lib/context.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import { Context, Effect, Operation, Scope } from "./types.ts";
import { Ok } from "./result.ts";
import { useScope } from "./scope.ts";
import { Do } from "./do.ts";

export function createContext<T>(name: string, defaultValue?: T): Context<T> {
let context: Context<T> = {
name,
defaultValue,
*get(): Operation<T | undefined> {
return (yield Get(context)) as T | undefined;
},
*set(value: T): Operation<T> {
return (yield Set(context, value)) as T;
},
*expect(): Operation<T> {
return (yield Expect(context)) as T;
},
*delete(): Operation<boolean> {
return (yield Delete(context)) as boolean;
},
get: () => Do(Get(context)),
set: (value) => Do(Set(context, value)),
expect: () => Do(Expect(context)),
delete: () => Do(Delete(context)),
*with<R>(value: T, operation: (value: T) => Operation<R>): Operation<R> {
let scope = yield* useScope();
let scope = yield* Do(UseScope((scope) => scope, "useScope()"));
let original = scope.hasOwn(context) ? scope.get(context) : undefined;
try {
return yield* operation(scope.set(context, value));
Expand All @@ -46,7 +38,7 @@ const Set = <T>(context: Context<T>, value: T) =>
const Expect = <T>(context: Context<T>) =>
UseScope((scope) => scope.expect(context), `expect(${context.name})`);
const Delete = <T>(context: Context<T>) =>
UseScope((scope) => scope.expect(context), `delete(${context.name})`);
UseScope((scope) => scope.delete(context), `delete(${context.name})`);

function UseScope<T>(fn: (scope: Scope) => T, description: string): Effect<T> {
return {
Expand Down
35 changes: 35 additions & 0 deletions lib/do.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Result } from "./result.ts";
import { Effect, Operation } from "./types.ts";

/**
* Perform a single Effect as an Operation
*/
export function Do<T>(effect: Effect<T>): Operation<T> {
return {
[Symbol.iterator]() {
let result: Result<T> | undefined = undefined;
let perform: Effect<T> = {
description: `do <${effect.description}>`,
enter(resolve, routine) {
return effect.enter((r) => {
resolve(result = r);
}, routine);
},
};

return {
next() {
if (result) {
if (result.ok) {
return { done: true, value: result.value };
} else {
throw result.error;
}
} else {
return { done: false, value: perform };
}
},
};
},
};
}

0 comments on commit c8a5eec

Please sign in to comment.