// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. /** Utility for representing n-tuple. Used in {@linkcode tee}. */ export type Tuple = N extends N ? number extends N ? T[] : TupleOf : never; /** Utility for representing n-tuple of. Used in {@linkcode Tuple}. */ export type TupleOf = R["length"] extends N ? R : TupleOf; interface QueueNode { value: T; next: QueueNode | undefined; } class Queue { #source: AsyncIterator; #queue: QueueNode; head: QueueNode; done: boolean; constructor(iterable: AsyncIterable) { this.#source = iterable[Symbol.asyncIterator](); this.#queue = { value: undefined!, next: undefined, }; this.head = this.#queue; this.done = false; } async next() { const result = await this.#source.next(); if (!result.done) { const nextNode: QueueNode = { value: result.value, next: undefined, }; this.#queue.next = nextNode; this.#queue = nextNode; } else { this.done = true; } } } /** * Branches the given async iterable into the `n` branches. * * @example * ```ts * import { tee } from "https://deno.land/std@$STD_VERSION/async/tee.ts"; * * const gen = async function* gen() { * yield 1; * yield 2; * yield 3; * }; * * const [branch1, branch2] = tee(gen()); * * for await (const n of branch1) { * console.log(n); // => 1, 2, 3 * } * * for await (const n of branch2) { * console.log(n); // => 1, 2, 3 * } * ``` */ export function tee( iterable: AsyncIterable, n: N = 2 as N, ): Tuple, N> { const queue = new Queue(iterable); async function* generator(): AsyncGenerator { let buffer = queue.head; while (true) { if (buffer.next) { buffer = buffer.next; yield buffer.value; } else if (queue.done) { return; } else { await queue.next(); } } } return Array.from({ length: n }).map( () => generator(), ) as Tuple< AsyncIterable, N >; }