export type Nullable = T | null | undefined; export function isDefined(obj: T): obj is NonNullable { return obj !== undefined && obj !== null; } export function isAsyncIterable(obj: any): obj is AsyncIterable { return isDefined(obj) && typeof obj[Symbol.asyncIterator] === "function"; } export function asArray(iterable: Iterable) { return Array.isArray(iterable) ? iterable : Array.from(iterable); } export function identity(obj: T) { return obj; } class WrappedAsyncIterator implements AsyncIterable { readonly #iterator: AsyncIterator; constructor(iterator: AsyncIterator) { this.#iterator = iterator; } [Symbol.asyncIterator]() { return this.#iterator; } } export function asAsyncIterable(iterator: AsyncIterator): AsyncIterable { return isAsyncIterable(iterator) ? iterator : new WrappedAsyncIterator(iterator); } const _emptyIterableIterator = new class EmptyIterableIterator implements IterableIterator { [Symbol.iterator]() { return this; } next(): IteratorResult { return { done: true, value: undefined }; } return(_value?: any): IteratorResult { throw new Error("Method not implemented."); } throw(_e?: any): IteratorResult { throw new Error("Method not implemented."); } }; export function emptyIterableIterator(): IterableIterator { return _emptyIterableIterator; } type FindElementSuccess = { found: true; element: T; }; type FindElementFail = { found: false; reason?: number; }; export type FindElementResult = FindElementSuccess | FindElementFail;