Skip to content

Instantly share code, notes, and snippets.

@Gozala
Created Aug 13, 2020
Embed
What would you like to do?
/**
* @template T, X, A
* @typedef {import('./protocol').Process<T, X, A>} Process
*/
/**
* @template X, T
* @typedef {import('./protocol').Task<X, T>} Task
*/
/**
* @template T
* @implements {AsyncIterable<T>}
*/
class Effect {
/**
* @template T - Message produced by performing a task.
* @template X - An error that task could produce.
* @template A - Result on succesful task completion.
* @param {Task<X, A>} task
* @param {(value:A) => T} succeed
* @param {(error:X) => T} fail
* @returns {Effect<T>}
*/
static perform (task, succeed, fail) {
return new Perfrom(task, succeed, fail)
}
/**
* @template T - Message produced by performing a task.
* @template M - Messaeg produced by the task.
* @template X - An error that task could produce.
* @template R - Result on succesful task completion.
* @param {() => Process<M, X, R>} task
* @param {(message:M) => T} send
* @param {(value:R) => T} succeed
* @param {(error:X) => T} fail
* @returns {Effect<T>}
*/
static spawn (task, send, succeed, fail) {
return new Spawn(task, send, succeed, fail)
}
/**
* @returns {AsyncIterator<T>}
*/
async * [Symbol.asyncIterator] () {
}
}
/**
* @template T, X, R
* @extends {Effect<T>}
*/
class Perfrom extends Effect {
/**
* @param {Task<X, R>} task
* @param {(value:R) => T} succeed
* @param {(error:X) => T} fail
*/
constructor (task, succeed, fail) {
super()
this.task = task
this.succeed = succeed
this.fail = fail
}
async * [Symbol.asyncIterator] () {
try {
const value = await this.task()
yield this.succeed(value)
} catch (error) {
yield this.fail(error)
}
}
}
/**
* @template T, M, X, R
* @extends {Effect<T>}
*/
class Spawn extends Effect {
/**
* @param {() => Process<M, X, R>} task
* @param {(message:M) => T} send
* @param {(value:R) => T} succeed
* @param {(error:X) => T} fail
*/
constructor (task, send, succeed, fail) {
super()
this.task = task
this.send = send
this.succeed = succeed
this.fail = fail
}
async * [Symbol.asyncIterator] () {
try {
const process = this.task()
while (true) {
const next = await process.next()
if (next.done) {
yield this.succeed(next.value)
break
} else {
yield this.send(next.value)
}
}
} catch (error) {
yield this.fail(error)
}
}
}
export interface Future<X, T> extends Promise<T> {
then(succeed: (value: T) => any, fail: (error: X) => any): any
}
export interface Process<M, X, T> extends AsyncGenerator<M, T, never> {
next(...args: []): Future<X, IteratorResult<M, T>>
}
export type Task<X, A> = () => Future<X, A>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment