import { CheckPromiseIterableType, CheckPromiseReturnType,
CheckIterableType, CheckPromiseType, PromiseReturnType, PureType } from "../types";
import { isPromise, exec } from "../utils";
import { AsyncIterableType, AsyncIteratorType } from "./asyncIterable";
/**
* @namespace iterable
*/
/**
* @memberof iterable
* @typedef
*/
export type IterableReturnType<T extends Iterable<any>, U> =
CheckPromiseReturnType<CheckIterableType<T>, U>;
/**
* @memberof iterable
* @typedef
*/
export type EachIterableCallbackType<T extends Iterable<any>, U> =
(value: CheckPromiseIterableType<T>, iterable: T) => U;
/**
* @memberof iterable
* @typedef
*/
export type ReduceIterableCallbackType<T, U, R extends Iterable<U | Promise<U>> = Iterable<U>> =
(previousValue: T, currentValue: U, iterable: R) => T;
export function reduceIterableF<T, U extends Iterable<any>>(
callbackFn: ReduceIterableCallbackType<T, CheckPromiseIterableType<U>, U>,
initial: T,
iterable: U,
): IterableReturnType<U, T>;
/**
* @memberof iterable
*/
export function reduceIterableF<T, U extends Iterable<any>>(
callbackFn: ReduceIterableCallbackType<T, CheckPromiseIterableType<U>, U>,
initial: T,
iterable: U,
): Promise<T> | T {
let cur: T | Promise<T> = initial;
for (const value of iterable) {
cur = exec(c => exec(v => callbackFn(c, v, iterable), value), cur);
}
return cur;
}
/**
* @memberof iterable
*/
export function eachIterableF<T extends Iterable<any>>(
callbackFn: EachIterableCallbackType<T, void>, iterable: T): T {
for (const value of iterable) {
exec(v => callbackFn(v, iterable), value);
}
return iterable;
}
export function mapIterableF<T extends Iterable<any>, U>(
callbackFn: EachIterableCallbackType<T, U>, iterable: T):
CheckPromiseType<CheckIterableType<T>, Iterable<U | Promise<U>>, Iterable<U>>;
/**
* @memberof iterable
*/
export function* mapIterableF<T extends Iterable<any>, U>(
callbackFn: EachIterableCallbackType<T, U>, iterable: T): Iterable<U | Promise<U>> {
for (const value of iterable) {
yield exec(v => callbackFn(v, iterable), value);
}
}
/**
* @memberof iterable
*/
export function* filterIterableF<T extends Iterable<any>>(
callbackFn: EachIterableCallbackType<T, boolean>,
iterable: T):
IterableIterator<CheckPromiseIterableType<T>> {
for (const value of iterable) {
exec(v => callbackFn(v, iterable), value) && (yield value);
}
}
/**
* @memberof iterable
*/
export function headIterable<T>(iterable: Iterable<T>): T {
for (const value of iterable) {
return value;
}
}
/**
* @memberof iterable
*/
export function tailIterable<T>(iterable: Iterable<T>): T {
let cur: T;
for (const value of iterable) {
cur = value;
}
return cur;
}
export function getIterator<T extends AsyncIterableType<any>>(iterable: T) {
return ((iterable as any)[Symbol.asyncIterator] || (iterable as any)[Symbol.asyncIterator])();
}
/**
* @memberof iterable
*/
export function takeIterableF<T>(length: number, iterable: AsyncIterableType<T>):
PromiseReturnType<Array<PureType<T>>> {
type t = PureType<T>;
const cur: t[] = [];
if (length === 0) {
return cur;
}
let i = 0;
function _result(result: IteratorResult<T>, iter: AsyncIteratorType<T>): t[] | Promise<T> {
if (result.done || i >= length) {
return cur;
}
++i;
const value = result.value;
if (isPromise(value)) {
return value.then(v => {
cur.push(v);
return _take(iter);
});
} else {
cur.push(value as any);
}
return cur;
}
function _take(iter: AsyncIteratorType<T>): any {
const result = iter.next();
return exec(r => _result(r, iter), result);
}
return _take(getIterator(iterable));
}