// enum TaskState { // Pending, // Running, // Aborted, // Completed, // Failed // } interface TaskState { } namespace TaskState { export interface Pending { kind: 'Pending' } export interface Running { kind: 'Running', } export interface Progress { message: string, isIndeterminate: boolean, current: number, max: number, elapsedMs: number } } type ExecutionContext = { run(c: Computation, params?: { updateRateMs: number }): Promise, subscribe(o: (p: string, compId: number) => void): void, requestAbort(compId: number): void } namespace ExecutionContext { // export interface Synchronous extends ExecutionContext { // run(c: Computation, params?: { updateRateMs: number }): Promise, // } // export interface Observable extends ExecutionContext { // run(c: Computation, params?: { updateRateMs: number }): Promise, // } export const Sync: ExecutionContext = 0 as any; } interface RuntimeContext { run(c: Computation, params?: { updateRateMs: number }): Promise, yield(name: string): Promise | void } // if no context is specified, use the synchronous one. interface Computation { (ctx: RuntimeContext): Promise, _id: number } function create(c: (ctx: RuntimeContext) => Promise): Computation { return 0 as any; } function constant(c: T) { return create(async ctx => c); } type MultistepFn = (params: P, step: (s: number) => Promise | void, ctx: RuntimeContext) => Promise type ComputationProvider = (params: P) => Computation function MultistepComputation(name: string, steps: string[], f: MultistepFn): ComputationProvider { return params => create(async ctx => f(params, n => ctx.yield(steps[n]), ctx)); } // if total count is specified, could automatically provide percentage type UniformlyChunkedFn = (chunkSize: number, state: S, totalCount?: number) => number type UniformlyChunkedProvider = (ctx: RuntimeContext, state: S) => Promise function UniformlyChunked(label: string, initialChunk: number, f: UniformlyChunkedFn): UniformlyChunkedProvider { // TODO: track average time required for single element and then determine chunk size based on that. return 0 as any; } type LineReaderState = { str: string, position: number, lines: string[] } const uniformPart = UniformlyChunked('Reading lines', 1000000, (size, state: LineReaderState) => { state.position += size; state.lines.push(''); return 0 /* number of lines read */; }); function readLines(str: string): Computation { return create(async ctx => { const state = (await uniformPart(ctx, { str, position: 0, lines: [] })); return state.lines; }); } const prependHiToLines = MultistepComputation('Hi prepend', ['Parse input', 'Prepend Hi'], async (p: string, step, ctx) => { await step(0); const lines = await readLines(p)(ctx); await step(1); const ret = lines.map(l => 'Hi ' + l); return ret; }); (async function() { const r = await ExecutionContext.Sync.run(prependHiToLines('1\n2'), { updateRateMs: 150 }); console.log(r) }())