"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EffectSuspendTotal = exports.EffectSuspendTotalTypeId = exports.EffectTotal = exports.EffectTotalTypeId = exports.Provide = exports.ProvideTypeId = exports.BracketOut = exports.BracketOutTypeId = exports.Bridge = exports.BridgeTypeId = exports.Fold = exports.FoldTypeId = exports.ConcatAll = exports.ConcatAllTypeId = exports.Ensuring = exports.EnsuringTypeId = exports.Emit = exports.EmitTypeId = exports.Effect = exports.EffectTypeId = exports.Halt = exports.HaltTypeId = exports.Done = exports.DoneTypeId = exports.Read = exports.ReadTypeId = exports.PipeTo = exports.PipeToTypeId = exports.concrete = exports.ContinuationFinalizer = exports.ContinuationFinalizerTypeId = exports.ContinuationK = exports.ContinuationKTypeId = exports.concreteContinuation = exports.Continuation = exports.Channel = void 0;
// ets_tracing: off
require("../../../../Operator");
const symbols_1 = require("./symbols");
/**
 * A `Channel` is a nexus of I/O operations, which supports both reading and writing.
 * A channel may read values of type `InElem` and write values of type `OutElem`.
 * When the channel finishes, it yields a value of type `OutDone`. A channel may fail with
 * a value of type `OutErr`.
 *
 * Channels are the foundation of Streams: both streams and sinks are built on channels.
 * Most users shouldn't have to use channels directly, as streams and sinks are much more convenient
 * and cover all common use cases. However, when adding new stream and sink operators, or doing
 * something highly specialized, it may be useful to use channels directly.
 *
 * Channels compose in a variety of ways:
 *
 *  - Piping. One channel can be piped to another channel, assuming the input type of the second
 *    is the same as the output type of the first.
 *  - Sequencing. The terminal value of one channel can be used to create another channel, and
 *    both the first channel and the function that makes the second channel can be composed into a
 *    channel.
 *  - Concating. The output of one channel can be used to create other channels, which are all
 *    concatenated together. The first channel and the function that makes the other channels can
 *    be composed into a channel.
 */
class Channel {
    constructor() {
        this[">>>"] = (that) => new PipeTo(() => this, () => that);
    }
}
exports.Channel = Channel;
class Continuation {
}
exports.Continuation = Continuation;
/**
 * @ets_optimize remove
 */
function concreteContinuation(_) {
    //
}
exports.concreteContinuation = concreteContinuation;
exports.ContinuationKTypeId = Symbol();
class ContinuationK extends Continuation {
    constructor(onSuccess, onHalt) {
        super();
        this.onSuccess = onSuccess;
        this.onHalt = onHalt;
        this._typeId = exports.ContinuationKTypeId;
    }
    onExit(exit) {
        switch (exit._tag) {
            case "Failure": {
                return this.onHalt(exit.cause);
            }
            case "Success": {
                return this.onSuccess(exit.value);
            }
        }
    }
}
exports.ContinuationK = ContinuationK;
exports.ContinuationFinalizerTypeId = Symbol();
class ContinuationFinalizer extends Continuation {
    constructor(finalizer) {
        super();
        this.finalizer = finalizer;
        this._typeId = exports.ContinuationFinalizerTypeId;
    }
}
exports.ContinuationFinalizer = ContinuationFinalizer;
/**
 * @ets_optimize remove
 */
function concrete(_) {
    //
}
exports.concrete = concrete;
exports.PipeToTypeId = Symbol();
class PipeTo extends Channel {
    constructor(left, right) {
        super();
        this.left = left;
        this.right = right;
        this._typeId = exports.PipeToTypeId;
    }
}
exports.PipeTo = PipeTo;
exports.ReadTypeId = Symbol();
class Read extends Channel {
    constructor(more, done) {
        super();
        this.more = more;
        this.done = done;
        this._typeId = exports.ReadTypeId;
    }
}
exports.Read = Read;
exports.DoneTypeId = Symbol();
class Done extends Channel {
    constructor(terminal) {
        super();
        this.terminal = terminal;
        this._typeId = exports.DoneTypeId;
    }
}
exports.Done = Done;
exports.HaltTypeId = Symbol();
class Halt extends Channel {
    constructor(error) {
        super();
        this.error = error;
        this._typeId = exports.HaltTypeId;
    }
}
exports.Halt = Halt;
exports.EffectTypeId = Symbol();
class Effect extends Channel {
    constructor(effect) {
        super();
        this.effect = effect;
        this._typeId = exports.EffectTypeId;
    }
}
exports.Effect = Effect;
exports.EmitTypeId = Symbol();
class Emit extends Channel {
    constructor(out) {
        super();
        this.out = out;
        this._typeId = exports.EmitTypeId;
    }
}
exports.Emit = Emit;
exports.EnsuringTypeId = Symbol();
class Ensuring extends Channel {
    constructor(channel, finalizer) {
        super();
        this.channel = channel;
        this.finalizer = finalizer;
        this._typeId = exports.EnsuringTypeId;
    }
}
exports.Ensuring = Ensuring;
exports.ConcatAllTypeId = Symbol();
class ConcatAll extends Channel {
    constructor(combineInners, combineAll, value, k) {
        super();
        this.combineInners = combineInners;
        this.combineAll = combineAll;
        this.value = value;
        this.k = k;
        this._typeId = exports.ConcatAllTypeId;
    }
}
exports.ConcatAll = ConcatAll;
exports.FoldTypeId = Symbol();
class Fold extends Channel {
    constructor(value, k) {
        super();
        this.value = value;
        this.k = k;
        this._typeId = exports.FoldTypeId;
    }
}
exports.Fold = Fold;
exports.BridgeTypeId = Symbol();
class Bridge extends Channel {
    constructor(input, channel) {
        super();
        this.input = input;
        this.channel = channel;
        this._typeId = exports.BridgeTypeId;
    }
}
exports.Bridge = Bridge;
exports.BracketOutTypeId = Symbol();
class BracketOut extends Channel {
    constructor(acquire, finalizer) {
        super();
        this.acquire = acquire;
        this.finalizer = finalizer;
        this._typeId = exports.BracketOutTypeId;
    }
}
exports.BracketOut = BracketOut;
exports.ProvideTypeId = Symbol();
class Provide extends Channel {
    constructor(env, channel) {
        super();
        this.env = env;
        this.channel = channel;
        this._typeId = exports.ProvideTypeId;
    }
}
exports.Provide = Provide;
exports.EffectTotalTypeId = Symbol();
class EffectTotal extends Channel {
    constructor(effect) {
        super();
        this.effect = effect;
        this._typeId = exports.EffectTotalTypeId;
    }
}
exports.EffectTotal = EffectTotal;
exports.EffectSuspendTotalTypeId = Symbol();
class EffectSuspendTotal extends Channel {
    constructor(effect) {
        super();
        this.effect = effect;
        this._typeId = exports.EffectSuspendTotalTypeId;
    }
}
exports.EffectSuspendTotal = EffectSuspendTotal;
//# sourceMappingURL=primitives.js.map