Skip to content

Instantly share code, notes, and snippets.

@n1ru4l
Created December 2, 2020 08:35
Show Gist options
  • Save n1ru4l/ba1055dccc9dcef79f366e57a9a98a3d to your computer and use it in GitHub Desktop.
Save n1ru4l/ba1055dccc9dcef79f366e57a9a98a3d to your computer and use it in GitHub Desktop.

Revisions

  1. n1ru4l created this gist Dec 2, 2020.
    58 changes: 58 additions & 0 deletions makePushPullAsyncIterableIterator.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@

    type Deferred<T> = {
    resolve: (value: T) => void;
    reject: (value: unknown) => void;
    promise: Promise<T>;
    };

    function createDeferred<T>(): Deferred<T> {
    const d = {} as Deferred<T>;
    d.promise = new Promise<T>((resolve, reject) => {
    d.resolve = resolve;
    d.reject = reject;
    });
    return d;
    }

    export function makePushPullAsyncIterableIterator<T>() {
    let isRunning = true;
    const pushQueue: Array<T> = [];

    let d = createDeferred<"FINISH" | "NEW_VALUE">();

    const iterator = (async function* PushPullAsyncIterableIterator(): AsyncIterableIterator<
    T
    > {
    while (true) {
    if (pushQueue.length > 0) {
    yield pushQueue.shift()!;
    } else {
    const res = await d.promise;
    if (res === "FINISH") {
    return;
    }
    }
    }
    })();

    function push(value: T) {
    if (isRunning === false) {
    // TODO: Should this throw?
    return;
    }

    pushQueue.push(value);
    d.resolve("NEW_VALUE");
    d = createDeferred();
    }

    const oReturn = iterator["return"]?.bind(iterator);
    iterator["return"] = (...args) => {
    d.resolve("FINISH");
    return (
    oReturn?.(...args) ?? Promise.resolve({ done: true, value: undefined })
    );
    };

    return [push, iterator] as const;
    }