import { __awaiter, __generator } from "tslib";
/**
 * Deduplicates an array by filtering it via a Set.
 * @notice Should not be used for deduplicating arrays of complex types.
 * @param array The array to deduplicate.
 * @returns A new array, filtered for uniqueness.
 */
export function dedupArray(array) {
    return Array.from(new Set(array));
}
/**
 * Splits an arbitrary array into a series of chunks.
 * @param array The array to chunk.
 * @param chunkSize The maximum size of any chunk within the array.
 * @returns A new array of chunked members.
 */
export function chunk(array, chunkSize) {
    var chunks = [];
    for (var i = 0; i < array.length; i += chunkSize) {
        chunks.push(array.slice(i, i + chunkSize));
    }
    return chunks;
}
/**
 * Returns the last index of an array that matches the given predicate.
 * @note Emulates Array.prototype.findLastIndex
 * @param array The array to search.
 * @param predicate The predicate function to apply to each element.
 * @returns The last index of the array that matches the predicate, or -1 if no element matches.
 */
export function findLastIndex(array, predicate) {
    for (var i = array.length - 1; i >= 0; i--) {
        if (predicate(array[i], i, array)) {
            return i;
        }
    }
    return -1;
}
/**
 * Returns the last element of an array that matches the given predicate.
 * @note Emulates Array.prototype.findLast
 * @param array The array to search.
 * @param predicate The predicate function to apply to each element.
 * @returns The last element of the array that matches the predicate, or undefined if no element matches.
 */
export function findLast(array, predicate) {
    var index = findLastIndex(array, predicate);
    return index >= 0 ? array[index] : undefined;
}
/**
 * Performs an asynchronous filter operation on an array. This function behaves like Array.prototype.filter, but
 * accepts an asynchronous predicate function.
 * @param array The array to filter.
 * @param predicate The asynchronous predicate function to apply to each element.
 * @returns A promise that resolves to an array of elements that match the predicate.
 */
export function filterAsync(array, predicate) {
    return __awaiter(this, void 0, void 0, function () {
        var results;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, Promise.all(array.map(predicate))];
                case 1:
                    results = _a.sent();
                    return [2 /*return*/, array.filter(function (_, index) { return results[index]; })];
            }
        });
    });
}
/**
 * Performs an asynchronous map operation on an array. This function behaves like Array.prototype.map, but accepts an
 * asynchronous mapper function.
 * @param array The array to map.
 * @param mapper The asynchronous mapper function to apply to each element.
 * @returns A promise that resolves to an array of mapped elements.
 */
export function mapAsync(array, mapper) {
    return Promise.all(array.map(mapper));
}
/**
 * Performs an asynchronous reduce operation on an array. This function behaves like Array.prototype.reduce, but
 * accepts an asynchronous reducer function.
 * @param array The array to reduce.
 * @param reducer The asynchronous reducer function to apply to each element.
 * @param initialValue The initial value of the accumulator.
 * @returns A promise that resolves to the final value of the accumulator.
 */
export function reduceAsync(array, reducer, initialValue) {
    return __awaiter(this, void 0, void 0, function () {
        var accumulator, i;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    accumulator = initialValue;
                    i = 0;
                    _a.label = 1;
                case 1:
                    if (!(i < array.length)) return [3 /*break*/, 4];
                    return [4 /*yield*/, reducer(accumulator, array[i], i, array)];
                case 2:
                    accumulator = _a.sent();
                    _a.label = 3;
                case 3:
                    i++;
                    return [3 /*break*/, 1];
                case 4: return [2 /*return*/, accumulator];
            }
        });
    });
}
/**
 * Performs an asynchronous forEach operation on an array. This function behaves like Array.prototype.forEach, but
 * accepts an asynchronous callback function.
 * @param array The array to iterate over.
 * @param callback The asynchronous callback function to apply to each element.
 * @returns A promise that resolves to void.
 */
export function forEachAsync(array, callback) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, mapAsync(array, callback)];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
/**
 * Performs an asynchronous some operation on an array. This function behaves like Array.prototype.some, but accepts
 * an asynchronous predicate function.
 * @param array The array to search.
 * @param predicate The asynchronous predicate function to apply to each element.
 * @returns A promise that resolves to true if any element matches the predicate, or false if no element matches.
 */
export function someAsync(array, predicate) {
    return __awaiter(this, void 0, void 0, function () {
        var results;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, mapAsync(array, predicate)];
                case 1:
                    results = _a.sent();
                    return [2 /*return*/, results.some(function (value) { return value; })];
            }
        });
    });
}
/**
 * Performs an asynchronous every operation on an array. This function behaves like Array.prototype.every, but accepts
 * an asynchronous predicate function.
 * @param array The array to test.
 * @param predicate The asynchronous predicate function to apply to each element.
 * @returns A promise that resolves to true if all elements match the predicate, or false if any element does not match.
 * @note This function uses De Morgan's law to convert the predicate to a negated predicate, and then uses someAsync.
 *       This is done because it is more efficient to short-circuit on the first false value than the first true value.
 */
export function everyAsync(array, predicate) {
    return __awaiter(this, void 0, void 0, function () {
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, someAsync(array, function (value, index, obj) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, predicate(value, index, obj)];
                            case 1: return [2 /*return*/, !(_a.sent())];
                        }
                    }); }); })];
                case 1: return [2 /*return*/, !(_a.sent())];
            }
        });
    });
}
/**
 * Performs an asynchronous includes operation on an array. This function behaves like Array.prototype.includes, but
 * accepts an asynchronous predicate function.
 * @param array The array to search.
 * @param predicate The asynchronous predicate function to apply to each element.
 * @returns A promise that resolves to true if any element matches the predicate, or false if no element matches.
 * @note This function uses someAsync.
 */
export function includesAsync(array, predicate) {
    return someAsync(array, predicate);
}
/**
 * A generic type guard for arrays of a specific type.
 * @param array The array to test.
 * @param predicate The type guard predicate function to apply to each element.
 * @returns True if the array is an array of the specified type, or false otherwise.
 * @note This function uses Array.prototype.every.
 */
export function isArrayOf(array, predicate) {
    return Array.isArray(array) && array.every(predicate);
}
/**
 * Checks if a value is a Uint8Array.
 * @param value The value to check.
 * @returns True if the value is a Uint8Array, false otherwise.
 */
export function isUint8Array(value) {
    return (Array.isArray(value) &&
        value.length > 0 &&
        value.every(function (item) { return typeof item === "number" && Number.isInteger(item) && item >= 0 && item < 256; }));
}
//# sourceMappingURL=ArrayUtils.js.map