"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.zipParRight_ = exports.zipParLeft = exports.zipParLeft_ = exports.zipPar = exports.zipPar_ = exports.zipLeft = exports.zipLeft_ = exports.zip = exports.zip_ = exports.unit = exports.toEither = exports.succeeded = exports.succeed = exports.orElseFail = exports.orElseFail_ = exports.mapErrorCause = exports.mapErrorCause_ = exports.mapError = exports.mapError_ = exports.map = exports.map_ = exports.interrupted = exports.interrupt = exports.halt = exports.getOrElse = exports.getOrElse_ = exports.fromOption = exports.fromEither = exports.fold = exports.fold_ = exports.flatten = exports.failCause = exports.fail = exports.exists = exports.exists_ = exports.die = exports.collectAllPar = exports.zipWith = exports.zipWith_ = exports.collectAll = exports.chain = exports.chain_ = exports.bimap = exports.bimap_ = exports.as = exports.as_ = exports.ap = exports.ap_ = exports.Success = exports.Failure = void 0;
exports.mapBoth = exports.mapBoth_ = exports.assertsFailure = exports.untraced = exports.zipRight = exports.zipRight_ = exports.zipParRight = void 0;
// ets_tracing: off
const C = __importStar(require("../Cause/core"));
const errors_1 = require("../Cause/errors");
const A = __importStar(require("../Collections/Immutable/Array"));
const Tp = __importStar(require("../Collections/Immutable/Tuple"));
const E = __importStar(require("../Either"));
const Function_1 = require("../Function");
const O = __importStar(require("../Option"));
const exit_1 = require("./exit");
var exit_2 = require("./exit");
Object.defineProperty(exports, "Failure", { enumerable: true, get: function () { return exit_2.Failure; } });
Object.defineProperty(exports, "Success", { enumerable: true, get: function () { return exit_2.Success; } });
/**
 * Applicative's ap
 */
function ap_(fa, fab) {
    return chain_(fab, (f) => map_(fa, (a) => f(a)));
}
exports.ap_ = ap_;
/**
 * Applicative's ap
 *
 * @ets_data_first ap_
 */
function ap(fa) {
    return (fab) => ap_(fa, fab);
}
exports.ap = ap;
/**
 * Replaces the success value with the one provided.
 */
function as_(exit, b) {
    return map_(exit, () => b);
}
exports.as_ = as_;
/**
 * Replaces the success value with the one provided.
 *
 * @ets_data_first as_
 */
function as(b) {
    return (exit) => as_(exit, b);
}
exports.as = as;
/**
 * Maps over both the error and value type.
 */
function bimap_(exit, f, g) {
    return (mapError(f)(map(g)(exit)));
}
exports.bimap_ = bimap_;
/**
 * Maps over both the error and value type.
 *
 * @ets_data_first bimap_
 */
function bimap(f, g) {
    return (exit) => bimap_(exit, f, g);
}
exports.bimap = bimap;
/**
 * Flat maps over the value type.
 */
function chain_(exit, f) {
    switch (exit._tag) {
        case "Failure": {
            return exit;
        }
        case "Success": {
            return f(exit.value);
        }
    }
}
exports.chain_ = chain_;
/**
 * Flat maps over the value type.
 *
 * @ets_data_first chain_
 */
function chain(f) {
    return (exit) => chain_(exit, f);
}
exports.chain = chain;
/**
 * Collects all the success states and merges sequentially the causes
 */
function collectAll(...exits) {
    return (O.map_(A.head(exits), (head) => (map(A.reverse)(A.reduce((map((x) => [x])(head)), (acc, el) => (zipWith(el, (acc, el) => [el, ...acc], C.then)(acc)))(A.dropLeft_(exits, 1))))));
}
exports.collectAll = collectAll;
/**
 * Zips this together with the specified result using the combination functions.
 */
function zipWith_(exit, that, f, g) {
    switch (exit._tag) {
        case "Failure": {
            switch (that._tag) {
                case "Success": {
                    return exit;
                }
                case "Failure": {
                    return halt(g(exit.cause, that.cause));
                }
            }
        }
        // eslint-disable-next-line no-fallthrough
        case "Success": {
            switch (that._tag) {
                case "Success": {
                    return succeed(f(exit.value, that.value));
                }
                case "Failure": {
                    return that;
                }
            }
        }
    }
}
exports.zipWith_ = zipWith_;
/**
 * Zips this together with the specified result using the combination functions.
 *
 * @ets_data_first zipWith_
 */
function zipWith(that, f, g) {
    return (exit) => zipWith_(exit, that, f, g);
}
exports.zipWith = zipWith;
/**
 * Collects all the success states and merges the causes in parallel
 */
function collectAllPar(...exits) {
    return (O.map_(A.head(exits), (head) => (map(A.reverse)(A.reduce((map((x) => [x])(head)), (acc, el) => (zipWith(el, (acc, el) => [el, ...acc], C.both)(acc)))(A.dropLeft_(exits, 1))))));
}
exports.collectAllPar = collectAllPar;
/**
 * Construct an Exit with an unchecked cause containing the specified error
 */
function die(error) {
    return halt(C.die(error));
}
exports.die = die;
/**
 * Returns f(a) if the exit is successful
 */
function exists_(exit, f) {
    return (fold(() => false, f)(exit));
}
exports.exists_ = exists_;
/**
 * Returns f(a) if the exit is successful
 *
 * @ets_data_first exists_
 */
function exists(f) {
    return (exit) => exists_(exit, f);
}
exports.exists = exists;
/**
 * Constructs a failed exit with the specified checked error
 */
function fail(e) {
    return halt(C.fail(e));
}
exports.fail = fail;
/**
 * Constructs a failed exit with the specified cause
 */
function failCause(cause) {
    return new exit_1.Failure(cause);
}
exports.failCause = failCause;
/**
 * Flatten nested Exits
 */
function flatten(exit) {
    return (chain(Function_1.identity)(exit));
}
exports.flatten = flatten;
/**
 * Folds over the value or cause.
 */
function fold_(exit, failed, succeed) {
    switch (exit._tag) {
        case "Success": {
            return succeed(exit.value);
        }
        case "Failure": {
            return failed(exit.cause);
        }
    }
}
exports.fold_ = fold_;
/**
 * Folds over the value or cause.
 *
 * @ets_data_first fold_
 */
function fold(failed, succeed) {
    return (exit) => fold_(exit, failed, succeed);
}
exports.fold = fold;
/**
 * Embeds Either's Error & Success in an Exit
 */
function fromEither(e) {
    return e._tag === "Left" ? fail(e.left) : succeed(e.right);
}
exports.fromEither = fromEither;
/**
 * Embeds an option result into an Exit with the specified error using onNone
 */
function fromOption(onNone) {
    return (a) => a._tag === "None" ? fail(onNone()) : succeed(a.value);
}
exports.fromOption = fromOption;
/**
 * Get successful result falling back to orElse result in case of failure
 */
function getOrElse_(exit, orElse) {
    switch (exit._tag) {
        case "Success": {
            return exit.value;
        }
        case "Failure": {
            return orElse(exit.cause);
        }
    }
}
exports.getOrElse_ = getOrElse_;
/**
 * Get successful result falling back to orElse result in case of failure
 *
 * @ets_data_first getOrElse_
 */
function getOrElse(orElse) {
    return (exit) => getOrElse_(exit, orElse);
}
exports.getOrElse = getOrElse;
/**
 * Constructs a failed exit with the specified cause
 */
function halt(cause) {
    return new exit_1.Failure(cause);
}
exports.halt = halt;
/**
 * Constructs an exit with the specified interruption state
 */
function interrupt(id) {
    return halt(C.interrupt(id));
}
exports.interrupt = interrupt;
/**
 * Returns if Exit contains an interruption state
 */
function interrupted(exit) {
    switch (exit._tag) {
        case "Success": {
            return false;
        }
        case "Failure": {
            return C.interrupted(exit.cause);
        }
    }
}
exports.interrupted = interrupted;
/**
 * Maps over the value type.
 */
function map_(exit, f) {
    return (chain((a) => succeed(f(a)))(exit));
}
exports.map_ = map_;
/**
 * Maps over the value type.
 *
 * @ets_data_first map_
 */
function map(f) {
    return (exit) => map_(exit, f);
}
exports.map = map;
/**
 * Maps over the error type.
 */
function mapError_(exit, f) {
    switch (exit._tag) {
        case "Failure": {
            return halt(C.map(f)(exit.cause));
        }
        case "Success": {
            return exit;
        }
    }
}
exports.mapError_ = mapError_;
/**
 * Maps over the error type.
 *
 * @ets_data_first mapError_
 */
function mapError(f) {
    return (exit) => mapError_(exit, f);
}
exports.mapError = mapError;
/**
 * Maps over the cause type.
 */
function mapErrorCause_(exit, f) {
    switch (exit._tag) {
        case "Failure": {
            return halt(f(exit.cause));
        }
        case "Success": {
            return exit;
        }
    }
}
exports.mapErrorCause_ = mapErrorCause_;
/**
 * Maps over the cause type.
 *
 * @ets_data_first mapErrorCause_
 */
function mapErrorCause(f) {
    return (exit) => mapErrorCause_(exit, f);
}
exports.mapErrorCause = mapErrorCause;
/**
 * Replaces the error value with the one provided.
 */
function orElseFail_(exit, e) {
    return (mapError(() => e)(exit));
}
exports.orElseFail_ = orElseFail_;
/**
 * Replaces the error value with the one provided.
 *
 * @ets_data_first orElseFail_
 */
function orElseFail(e) {
    return (exit) => orElseFail_(exit, e);
}
exports.orElseFail = orElseFail;
/**
 * Construct a succeeded exit with the specified value
 */
function succeed(a) {
    return new exit_1.Success(a);
}
exports.succeed = succeed;
/**
 * Returns if an exit is succeeded
 */
function succeeded(exit) {
    switch (exit._tag) {
        case "Failure": {
            return false;
        }
        case "Success": {
            return true;
        }
    }
}
exports.succeeded = succeeded;
/**
 * Converts the `Exit` to an `Either<FiberFailure, A>`, by wrapping the
 * cause in `FiberFailure` (if the result is failed).
 */
function toEither(exit) {
    switch (exit._tag) {
        case "Success": {
            return E.right(exit.value);
        }
        case "Failure": {
            return E.left(new errors_1.FiberFailure(exit.cause));
        }
    }
}
exports.toEither = toEither;
/**
 * Discards the value.
 */
exports.unit = succeed(undefined);
/**
 * Sequentially zips the this result with the specified result or else returns the failed `Cause[E1]`
 */
function zip_(exit, that) {
    return (zipWith(that, (a, b) => Tp.tuple(a, b), C.then)(exit));
}
exports.zip_ = zip_;
/**
 * Sequentially zips the this result with the specified result or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zip_
 */
function zip(that) {
    return (exit) => zip_(exit, that);
}
exports.zip = zip;
/**
 * Sequentially zips the this result with the specified result discarding the second element of the tuple or else returns the failed `Cause[E1]`
 */
function zipLeft_(exit, that) {
    return (zipWith(that, (a, _) => a, C.then)(exit));
}
exports.zipLeft_ = zipLeft_;
/**
 * Sequentially zips the this result with the specified result discarding the second element of the tuple or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zipLeft_
 */
function zipLeft(that) {
    return (exit) => zipLeft_(exit, that);
}
exports.zipLeft = zipLeft;
/**
 * Parallelly zips the this result with the specified result or else returns the failed `Cause[E1]`
 */
function zipPar_(exit, that) {
    return (zipWith(that, (a, b) => Tp.tuple(a, b), C.both)(exit));
}
exports.zipPar_ = zipPar_;
/**
 * Parallelly zips the this result with the specified result or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zipPar_
 */
function zipPar(that) {
    return (exit) => zipPar_(exit, that);
}
exports.zipPar = zipPar;
/**
 * Parallelly zips the this result with the specified result discarding the second element of the tuple or else returns the failed `Cause[E1]`
 */
function zipParLeft_(exit, that) {
    return (zipWith(that, (a, _) => a, C.both)(exit));
}
exports.zipParLeft_ = zipParLeft_;
/**
 * Parallelly zips the this result with the specified result discarding the second element of the tuple or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zipParLeft_
 */
function zipParLeft(that) {
    return (exit) => zipParLeft_(exit, that);
}
exports.zipParLeft = zipParLeft;
/**
 * Parallelly zips the this result with the specified result discarding the first element of the tuple or else returns the failed `Cause[E1]`
 */
function zipParRight_(exit, that) {
    return (zipWith(that, (_, b) => b, C.both)(exit));
}
exports.zipParRight_ = zipParRight_;
/**
 * Parallelly zips the this result with the specified result discarding the first element of the tuple or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zipParRight_
 */
function zipParRight(that) {
    return (exit) => zipParRight_(exit, that);
}
exports.zipParRight = zipParRight;
/**
 * Sequentially zips the this result with the specified result discarding the first element of the tuple or else returns the failed `Cause[E1]`
 */
function zipRight_(exit, that) {
    return (zipWith(that, (_, b) => b, C.then)(exit));
}
exports.zipRight_ = zipRight_;
/**
 * Sequentially zips the this result with the specified result discarding the first element of the tuple or else returns the failed `Cause[E1]`
 *
 * @ets_data_first zipRight_
 */
function zipRight(that) {
    return (exit) => zipRight_(exit, that);
}
exports.zipRight = zipRight;
/**
 * Returns an untraced exit value.
 */
function untraced(self) {
    return self._tag === "Success" ? self : halt(C.untraced(self.cause));
}
exports.untraced = untraced;
/**
 * Asserts an exit is a failure
 */
function assertsFailure(exit) {
    if (exit._tag === "Success") {
        throw new Error("expected a failed exit and got success");
    }
}
exports.assertsFailure = assertsFailure;
/**
 * Maps over both the error and value type.
 */
function mapBoth_(self, f, g) {
    return map_(mapError_(self, f), g);
}
exports.mapBoth_ = mapBoth_;
/**
 * Maps over both the error and value type.
 *
 * @ets_data_first mapBoth_
 */
function mapBoth(f, g) {
    return (self) => mapBoth_(self, f, g);
}
exports.mapBoth = mapBoth;
//# sourceMappingURL=core.js.map