"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.suspend = exports.succeedWith = exports.unit = exports.unwrapManaged = exports.unwrap = exports.flatten = exports.managedOut = exports.fromEffect = exports.drain = exports.chain = exports.chain_ = exports.provideAll = exports.provideAll_ = exports.bracketOutExit = exports.bracketOutExit_ = exports.embedInput = exports.embedInput_ = exports.foldCauseChannel = exports.foldCauseChannel_ = exports.concatMap = exports.concatMap_ = exports.concatAllWith = exports.concatAllWith_ = exports.concatMapWith = exports.concatMapWith_ = exports.ensuringWith = exports.ensuringWith_ = exports.write = exports.writeWith = exports.dieWith = exports.die = exports.fail = exports.failWith = exports.failCause = exports.failCauseWith = exports.end = exports.endWith = exports.readWith = exports.readWithCause = exports.pipeTo = exports.pipeTo_ = void 0;
// ets_tracing: off
require("../../../Operator");
const Cause = __importStar(require("../../../Cause"));
const Tp = __importStar(require("../../../Collections/Immutable/Tuple"));
const T = __importStar(require("../../../Effect"));
const E = __importStar(require("../../../Either"));
const Function_1 = require("../../../Function");
const ReleaseMap = __importStar(require("../../../Managed/ReleaseMap"));
const P = __importStar(require("./_internal/primitives"));
const primitives_1 = require("./_internal/primitives");
/**
 * Pipe the output of a channel into the input of another
 */
function pipeTo_(left, right) {
    return new primitives_1.PipeTo(() => left, () => right);
}
exports.pipeTo_ = pipeTo_;
/**
 * Pipe the output of a channel into the input of another
 *
 * @ets_data_first pipeTo_
 */
function pipeTo(right) {
    return (left) => pipeTo_(left, right);
}
exports.pipeTo = pipeTo;
/**
 * Reads an input and continue exposing both full error cause and completion
 */
function readWithCause(inp, halt, done) {
    return new primitives_1.Read(inp, new P.ContinuationK(done, halt));
}
exports.readWithCause = readWithCause;
/**
 * Reads an input and continue exposing both error and completion
 */
function readWith(inp, error, done) {
    return readWithCause(inp, (c) => E.fold_(Cause.failureOrCause(c), error, failCause), done);
}
exports.readWith = readWith;
/**
 * End a channel with the specified result
 */
function endWith(result) {
    return new primitives_1.Done(result);
}
exports.endWith = endWith;
/**
 * End a channel with the specified result
 */
function end(result) {
    return new primitives_1.Done(() => result);
}
exports.end = end;
/**
 * Halt a channel with the specified cause
 */
function failCauseWith(result) {
    return new primitives_1.Halt(result);
}
exports.failCauseWith = failCauseWith;
/**
 * Halt a channel with the specified cause
 */
function failCause(result) {
    return new primitives_1.Halt(() => result);
}
exports.failCause = failCause;
/**
 * Halt a channel with the specified error
 */
function failWith(error) {
    return new primitives_1.Halt(() => Cause.fail(error()));
}
exports.failWith = failWith;
/**
 * Halt a channel with the specified error
 */
function fail(error) {
    return new primitives_1.Halt(() => Cause.fail(error));
}
exports.fail = fail;
/**
 * Halt a channel with the specified exception
 */
function die(defect) {
    return new primitives_1.Halt(() => Cause.die(defect));
}
exports.die = die;
/**
 * Halt a channel with the specified exception
 */
function dieWith(defect) {
    return new primitives_1.Halt(() => Cause.die(defect()));
}
exports.dieWith = dieWith;
/**
 * Writes an output to the channel
 */
function writeWith(out) {
    return new primitives_1.Emit(out);
}
exports.writeWith = writeWith;
/**
 * Writes an output to the channel
 */
function write(out) {
    return new primitives_1.Emit(() => out);
}
exports.write = write;
/**
 * Returns a new channel with an attached finalizer. The finalizer is guaranteed to be executed
 * so long as the channel begins execution (and regardless of whether or not it completes).
 */
function ensuringWith_(channel, finalizer) {
    return new primitives_1.Ensuring(channel, finalizer);
}
exports.ensuringWith_ = ensuringWith_;
/**
 * Returns a new channel with an attached finalizer. The finalizer is guaranteed to be executed
 * so long as the channel begins execution (and regardless of whether or not it completes).
 *
 * @ets_data_first ensuringWith_
 */
function ensuringWith(finalizer) {
    return (channel) => ensuringWith_(channel, finalizer);
}
exports.ensuringWith = ensuringWith;
/**
 * Returns a new channel whose outputs are fed to the specified factory function, which creates
 * new channels in response. These new channels are sequentially concatenated together, and all
 * their outputs appear as outputs of the newly returned channel. The provided merging function
 * is used to merge the terminal values of all channels into the single terminal value of the
 * returned channel.
 */
function concatMapWith_(self, f, g, h) {
    return new primitives_1.ConcatAll(g, h, self, f);
}
exports.concatMapWith_ = concatMapWith_;
/**
 * Returns a new channel whose outputs are fed to the specified factory function, which creates
 * new channels in response. These new channels are sequentially concatenated together, and all
 * their outputs appear as outputs of the newly returned channel. The provided merging function
 * is used to merge the terminal values of all channels into the single terminal value of the
 * returned channel.
 *
 * @ets_data_first concatMapWith_
 */
function concatMapWith(f, g, h) {
    return (self) => concatMapWith_(self, f, g, h);
}
exports.concatMapWith = concatMapWith;
/**
 * Concat sequentially a channel of channels
 */
function concatAllWith_(channels, f, g) {
    return new primitives_1.ConcatAll(f, g, channels, Function_1.identity);
}
exports.concatAllWith_ = concatAllWith_;
/**
 * Concat sequentially a channel of channels
 *
 * @ets_data_first concatAllWith_
 */
function concatAllWith(f, g) {
    return (channels) => concatAllWith_(channels, f, g);
}
exports.concatAllWith = concatAllWith;
/**
 * Returns a new channel whose outputs are fed to the specified factory function, which creates
 * new channels in response. These new channels are sequentially concatenated together, and all
 * their outputs appear as outputs of the newly returned channel.
 */
function concatMap_(self, f) {
    return concatMapWith_(self, f, () => void 0, () => void 0);
}
exports.concatMap_ = concatMap_;
/**
 * Returns a new channel whose outputs are fed to the specified factory function, which creates
 * new channels in response. These new channels are sequentially concatenated together, and all
 * their outputs appear as outputs of the newly returned channel.
 *
 * @ets_data_first concatMap_
 */
function concatMap(f) {
    return (self) => concatMap_(self, f);
}
exports.concatMap = concatMap;
/**
 * Fold the channel exposing success and full error cause
 */
function foldCauseChannel_(self, onErr, onSucc) {
    return new primitives_1.Fold(self, new P.ContinuationK(onSucc, onErr));
}
exports.foldCauseChannel_ = foldCauseChannel_;
/**
 * Fold the channel exposing success and full error cause
 *
 * @ets_data_first foldCauseChannel_
 */
function foldCauseChannel(onErr, onSucc) {
    return (self) => foldCauseChannel_(self, onErr, onSucc);
}
exports.foldCauseChannel = foldCauseChannel;
/**
 * Embed inputs from continuos pulling of a producer
 */
function embedInput_(self, input) {
    return new primitives_1.Bridge(input, self);
}
exports.embedInput_ = embedInput_;
/**
 * Embed inputs from continuos pulling of a producer
 *
 * @ets_data_first embedInput_
 */
function embedInput(input) {
    return (self) => embedInput_(self, input);
}
exports.embedInput = embedInput;
/**
 * Construct a resource Channel with Acquire / Release
 */
function bracketOutExit_(self, release) {
    return new primitives_1.BracketOut(self, release);
}
exports.bracketOutExit_ = bracketOutExit_;
/**
 * Construct a resource Channel with Acquire / Release
 *
 * @ets_data_first bracketOutExit_
 */
function bracketOutExit(release) {
    return (self) => bracketOutExit_(self, release);
}
exports.bracketOutExit = bracketOutExit;
/**
 * Provides the channel with its required environment, which eliminates
 * its dependency on `Env`.
 */
function provideAll_(self, env) {
    return new primitives_1.Provide(env, self);
}
exports.provideAll_ = provideAll_;
/**
 * Provides the channel with its required environment, which eliminates
 * its dependency on `Env`.
 *
 * @ets_data_first provideAll_
 */
function provideAll(env) {
    return (self) => provideAll_(self, env);
}
exports.provideAll = provideAll;
/**
 * Returns a new channel, which sequentially combines this channel, together with the provided
 * factory function, which creates a second channel based on the terminal value of this channel.
 * The result is a channel that will first perform the functions of this channel, before
 * performing the functions of the created channel (including yielding its terminal value).
 */
function chain_(self, f) {
    return new P.Fold(self, new P.ContinuationK(f, failCause));
}
exports.chain_ = chain_;
/**
 * Returns a new channel, which sequentially combines this channel, together with the provided
 * factory function, which creates a second channel based on the terminal value of this channel.
 * The result is a channel that will first perform the functions of this channel, before
 * performing the functions of the created channel (including yielding its terminal value).
 *
 * @ets_data_first chain_
 */
function chain(f) {
    return (self) => chain_(self, f);
}
exports.chain = chain;
/**
 * Returns a new channel which reads all the elements from upstream's output channel
 * and ignores them, then terminates with the upstream result value.
 */
function drain(self) {
    const drainer = readWithCause((_) => drainer, failCause, end);
    return self[">>>"](drainer);
}
exports.drain = drain;
/**
 * Use an effect to end a channel
 */
function fromEffect(self) {
    return new P.Effect(self);
}
exports.fromEffect = fromEffect;
/**
 * Use a managed to emit an output element
 */
function managedOut(self) {
    return concatMap_(bracketOutExit_(ReleaseMap.makeReleaseMap, (rm, ex) => ReleaseMap.releaseAll(ex, T.sequential)(rm)), (rm) => chain_(fromEffect(T.map_(T.provideSome_(self.effect, (r) => Tp.tuple(r, rm)), Tp.get(1))), write));
}
exports.managedOut = managedOut;
/**
 * Returns a new channel, which flattens the terminal value of this channel. This function may
 * only be called if the terminal value of this channel is another channel of compatible types.
 */
function flatten(self) {
    return chain_(self, Function_1.identity);
}
exports.flatten = flatten;
/**
 * Makes a channel from an effect that returns a channel in case of success
 */
function unwrap(self) {
    return flatten(fromEffect(self));
}
exports.unwrap = unwrap;
/**
 * Makes a channel from a managed that returns a channel in case of success
 */
function unwrapManaged(self) {
    return concatAllWith_(managedOut(self), Function_1.identity, Function_1.identity);
}
exports.unwrapManaged = unwrapManaged;
/**
 * Unit channel
 */
exports.unit = end(void 0);
function succeedWith(effect) {
    return new P.EffectTotal(effect);
}
exports.succeedWith = succeedWith;
function suspend(effect) {
    return new P.EffectSuspendTotal(effect);
}
exports.suspend = suspend;
//# sourceMappingURL=core.js.map