export function* enumerate<T>(iterator: Iterable<T>) {
	let index = 0;
	for (const item of iterator) yield [index++, item] as const;
}

export function* zip<A, B>(iterable_a: Iterable<A>, iterable_b: Iterable<B>) {
	const iter_a = iterable_a[Symbol.iterator]();
	const iter_b = iterable_b[Symbol.iterator]();
	while (true) {
		const next_a = iter_a.next().value;
		const next_b = iter_b.next().value;
		if (next_a === undefined) return;
		if (next_b === undefined) return;
		yield [next_a as A, next_b as B] as const;
	}
}

export function* range(from: number, to: number) {
	while (from < to) yield from++;
}

export async function wait(ms: number) {
	await new Promise((resolver) => setTimeout(resolver, ms));
}

export type Awaitable<T> = T | Promise<T>;

export function last<T>(iterable: Iterable<T>) {
	let last = undefined as T | undefined;
	for (const item of iterable) last = item;
	return last;
}
