effect
Version:
The missing standard library for TypeScript, for writing production-grade software.
967 lines • 134 kB
JavaScript
import * as Cause from "../Cause.js";
import * as Chunk from "../Chunk.js";
import * as Clock from "../Clock.js";
import * as Context from "../Context.js";
import * as Deferred from "../Deferred.js";
import * as Duration from "../Duration.js";
import * as Effect from "../Effect.js";
import * as Either from "../Either.js";
import * as Equal from "../Equal.js";
import * as Exit from "../Exit.js";
import * as Fiber from "../Fiber.js";
import * as FiberRef from "../FiberRef.js";
import { constTrue, dual, identity, pipe } from "../Function.js";
import * as Layer from "../Layer.js";
import * as MergeDecision from "../MergeDecision.js";
import * as Option from "../Option.js";
import { pipeArguments } from "../Pipeable.js";
import { hasProperty } from "../Predicate.js";
import * as PubSub from "../PubSub.js";
import * as Queue from "../Queue.js";
import * as RcRef from "../RcRef.js";
import * as Ref from "../Ref.js";
import * as Runtime from "../Runtime.js";
import * as Schedule from "../Schedule.js";
import * as HaltStrategy from "../StreamHaltStrategy.js";
import * as TPubSub from "../TPubSub.js";
import * as TQueue from "../TQueue.js";
import * as Tuple from "../Tuple.js";
import * as channel from "./channel.js";
import * as channelExecutor from "./channel/channelExecutor.js";
import * as MergeStrategy from "./channel/mergeStrategy.js";
import * as core from "./core-stream.js";
import * as doNotation from "./doNotation.js";
import { RingBuffer } from "./ringBuffer.js";
import * as sink_ from "./sink.js";
import * as DebounceState from "./stream/debounceState.js";
import * as emit from "./stream/emit.js";
import * as haltStrategy from "./stream/haltStrategy.js";
import * as Handoff from "./stream/handoff.js";
import * as HandoffSignal from "./stream/handoffSignal.js";
import * as pull from "./stream/pull.js";
import * as SinkEndReason from "./stream/sinkEndReason.js";
import * as ZipAllState from "./stream/zipAllState.js";
import * as ZipChunksState from "./stream/zipChunksState.js";
import * as InternalTake from "./take.js";
import * as InternalTracer from "./tracer.js";
/** @internal */
const StreamSymbolKey = "effect/Stream";
/** @internal */
export const StreamTypeId = /*#__PURE__*/Symbol.for(StreamSymbolKey);
/** @internal */
const streamVariance = {
_R: _ => _,
_E: _ => _,
_A: _ => _
};
/** @internal */
export class StreamImpl {
channel;
[StreamTypeId] = streamVariance;
constructor(channel) {
this.channel = channel;
}
pipe() {
return pipeArguments(this, arguments);
}
}
/** @internal */
export const isStream = u => hasProperty(u, StreamTypeId) || Effect.isEffect(u);
/** @internal */
export const DefaultChunkSize = 4096;
/** @internal */
export const accumulate = self => chunks(accumulateChunks(self));
/** @internal */
export const accumulateChunks = self => {
const accumulator = s => core.readWith({
onInput: input => {
const next = Chunk.appendAll(s, input);
return core.flatMap(core.write(next), () => accumulator(next));
},
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(core.pipeTo(toChannel(self), accumulator(Chunk.empty())));
};
/** @internal */
export const acquireRelease = (acquire, release) => scoped(Effect.acquireRelease(acquire, release));
/** @internal */
export const aggregate = /*#__PURE__*/dual(2, (self, sink) => aggregateWithin(self, sink, Schedule.forever));
/** @internal */
export const aggregateWithin = /*#__PURE__*/dual(3, (self, sink, schedule) => filterMap(aggregateWithinEither(self, sink, schedule), _ => Either.match(_, {
onLeft: Option.none,
onRight: Option.some
})));
/** @internal */
export const aggregateWithinEither = /*#__PURE__*/dual(3, (self, sink, schedule) => {
const layer = Effect.all([Handoff.make(), Ref.make(SinkEndReason.ScheduleEnd), Ref.make(Chunk.empty()), Schedule.driver(schedule), Ref.make(false), Ref.make(false)]);
return fromEffect(layer).pipe(flatMap(([handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, endAfterEmit]) => {
const handoffProducer = core.readWithCause({
onInput: input => core.flatMap(core.fromEffect(pipe(handoff, Handoff.offer(HandoffSignal.emit(input)), Effect.when(() => Chunk.isNonEmpty(input)))), () => handoffProducer),
onFailure: cause => core.fromEffect(Handoff.offer(handoff, HandoffSignal.halt(cause))),
onDone: () => core.fromEffect(Handoff.offer(handoff, HandoffSignal.end(SinkEndReason.UpstreamEnd)))
});
const handoffConsumer = pipe(Ref.getAndSet(sinkLeftovers, Chunk.empty()), Effect.flatMap(leftovers => {
if (Chunk.isNonEmpty(leftovers)) {
return pipe(Ref.set(consumed, true), Effect.zipRight(Effect.succeed(pipe(core.write(leftovers), core.flatMap(() => handoffConsumer)))));
}
return pipe(Handoff.take(handoff), Effect.map(signal => {
switch (signal._tag) {
case HandoffSignal.OP_EMIT:
{
return pipe(core.fromEffect(Ref.set(consumed, true)), channel.zipRight(core.write(signal.elements)), channel.zipRight(core.fromEffect(Ref.get(endAfterEmit))), core.flatMap(bool => bool ? core.void : handoffConsumer));
}
case HandoffSignal.OP_HALT:
{
return core.failCause(signal.cause);
}
case HandoffSignal.OP_END:
{
if (signal.reason._tag === SinkEndReason.OP_SCHEDULE_END) {
return pipe(Ref.get(consumed), Effect.map(bool => bool ? core.fromEffect(pipe(Ref.set(sinkEndReason, SinkEndReason.ScheduleEnd), Effect.zipRight(Ref.set(endAfterEmit, true)))) : pipe(core.fromEffect(pipe(Ref.set(sinkEndReason, SinkEndReason.ScheduleEnd), Effect.zipRight(Ref.set(endAfterEmit, true)))), core.flatMap(() => handoffConsumer))), channel.unwrap);
}
return pipe(Ref.set(sinkEndReason, signal.reason), Effect.zipRight(Ref.set(endAfterEmit, true)), core.fromEffect);
}
}
}));
}), channel.unwrap);
const timeout = lastB => scheduleDriver.next(lastB);
const scheduledAggregator = (sinkFiber, scheduleFiber, scope) => {
const forkSink = pipe(Ref.set(consumed, false), Effect.zipRight(Ref.set(endAfterEmit, false)), Effect.zipRight(pipe(handoffConsumer, channel.pipeToOrFail(sink_.toChannel(sink)), core.collectElements, channel.run, Effect.forkIn(scope))));
const handleSide = (leftovers, b, c) => pipe(Ref.set(sinkLeftovers, Chunk.flatten(leftovers)), Effect.zipRight(Effect.map(Ref.get(sinkEndReason), reason => {
switch (reason._tag) {
case SinkEndReason.OP_SCHEDULE_END:
{
return pipe(Effect.all([Ref.get(consumed), forkSink, pipe(timeout(Option.some(b)), Effect.forkIn(scope))]), Effect.map(([wasConsumed, sinkFiber, scheduleFiber]) => {
const toWrite = pipe(c, Option.match({
onNone: () => Chunk.of(Either.right(b)),
onSome: c => Chunk.make(Either.right(b), Either.left(c))
}));
if (wasConsumed) {
return pipe(core.write(toWrite), core.flatMap(() => scheduledAggregator(sinkFiber, scheduleFiber, scope)));
}
return scheduledAggregator(sinkFiber, scheduleFiber, scope);
}), channel.unwrap);
}
case SinkEndReason.OP_UPSTREAM_END:
{
return pipe(Ref.get(consumed), Effect.map(wasConsumed => wasConsumed ? core.write(Chunk.of(Either.right(b))) : core.void), channel.unwrap);
}
}
})), channel.unwrap);
return channel.unwrap(Effect.raceWith(Fiber.join(sinkFiber), Fiber.join(scheduleFiber), {
onSelfDone: (sinkExit, _) => pipe(Fiber.interrupt(scheduleFiber), Effect.zipRight(pipe(Effect.suspend(() => sinkExit), Effect.map(([leftovers, b]) => handleSide(leftovers, b, Option.none()))))),
onOtherDone: (scheduleExit, _) => Effect.matchCauseEffect(Effect.suspend(() => scheduleExit), {
onFailure: cause => Either.match(Cause.failureOrCause(cause), {
onLeft: () => pipe(handoff, Handoff.offer(HandoffSignal.end(SinkEndReason.ScheduleEnd)), Effect.forkDaemon, Effect.zipRight(pipe(Fiber.join(sinkFiber), Effect.map(([leftovers, b]) => handleSide(leftovers, b, Option.none()))))),
onRight: cause => pipe(handoff, Handoff.offer(HandoffSignal.halt(cause)), Effect.forkDaemon, Effect.zipRight(pipe(Fiber.join(sinkFiber), Effect.map(([leftovers, b]) => handleSide(leftovers, b, Option.none())))))
}),
onSuccess: c => pipe(handoff, Handoff.offer(HandoffSignal.end(SinkEndReason.ScheduleEnd)), Effect.forkDaemon, Effect.zipRight(pipe(Fiber.join(sinkFiber), Effect.map(([leftovers, b]) => handleSide(leftovers, b, Option.some(c))))))
})
}));
};
return unwrapScopedWith(scope => core.pipeTo(toChannel(self), handoffProducer).pipe(channel.run, Effect.forkIn(scope), Effect.zipRight(channel.pipeToOrFail(handoffConsumer, sink_.toChannel(sink)).pipe(core.collectElements, channel.run, Effect.forkIn(scope), Effect.flatMap(sinkFiber => timeout(Option.none()).pipe(Effect.forkIn(scope), Effect.map(scheduleFiber => new StreamImpl(scheduledAggregator(sinkFiber, scheduleFiber, scope)))))))));
}));
});
/** @internal */
export const as = /*#__PURE__*/dual(2, (self, value) => map(self, () => value));
const queueFromBufferOptions = bufferSize => {
if (bufferSize === "unbounded") {
return Queue.unbounded();
} else if (typeof bufferSize === "number" || bufferSize === undefined) {
return Queue.bounded(bufferSize ?? 16);
}
switch (bufferSize.strategy) {
case "dropping":
return Queue.dropping(bufferSize.bufferSize ?? 16);
case "sliding":
return Queue.sliding(bufferSize.bufferSize ?? 16);
default:
return Queue.bounded(bufferSize.bufferSize ?? 16);
}
};
/** @internal */
export const _async = (register, bufferSize) => Effect.acquireRelease(queueFromBufferOptions(bufferSize), queue => Queue.shutdown(queue)).pipe(Effect.flatMap(output => Effect.runtime().pipe(Effect.flatMap(runtime => Effect.sync(() => {
const runPromiseExit = Runtime.runPromiseExit(runtime);
const canceler = register(emit.make(resume => InternalTake.fromPull(resume).pipe(Effect.flatMap(take => Queue.offer(output, take)), Effect.asVoid, runPromiseExit).then(exit => {
if (Exit.isFailure(exit)) {
if (!Cause.isInterrupted(exit.cause)) {
throw Cause.squash(exit.cause);
}
}
})));
return canceler;
})), Effect.map(value => {
const loop = Queue.take(output).pipe(Effect.flatMap(take => InternalTake.done(take)), Effect.match({
onFailure: maybeError => core.fromEffect(Queue.shutdown(output)).pipe(channel.zipRight(Option.match(maybeError, {
onNone: () => core.void,
onSome: error => core.fail(error)
}))),
onSuccess: chunk => core.write(chunk).pipe(core.flatMap(() => loop))
}), channel.unwrap);
return fromChannel(loop).pipe(ensuring(value ?? Effect.void));
}))), unwrapScoped);
/** @internal */
export const asyncEffect = (register, bufferSize) => pipe(Effect.acquireRelease(queueFromBufferOptions(bufferSize), queue => Queue.shutdown(queue)), Effect.flatMap(output => pipe(Effect.runtime(), Effect.flatMap(runtime => pipe(register(emit.make(k => pipe(InternalTake.fromPull(k), Effect.flatMap(take => Queue.offer(output, take)), Effect.asVoid, Runtime.runPromiseExit(runtime)).then(exit => {
if (Exit.isFailure(exit)) {
if (!Cause.isInterrupted(exit.cause)) {
throw Cause.squash(exit.cause);
}
}
}))), Effect.map(() => {
const loop = pipe(Queue.take(output), Effect.flatMap(InternalTake.done), Effect.match({
onFailure: maybeError => pipe(core.fromEffect(Queue.shutdown(output)), channel.zipRight(Option.match(maybeError, {
onNone: () => core.void,
onSome: core.fail
}))),
onSuccess: chunk => pipe(core.write(chunk), core.flatMap(() => loop))
}), channel.unwrap);
return loop;
}))))), channel.unwrapScoped, fromChannel);
const queueFromBufferOptionsPush = options => {
if (options?.bufferSize === "unbounded" || options?.bufferSize === undefined && options?.strategy === undefined) {
return Queue.unbounded();
}
switch (options?.strategy) {
case "sliding":
return Queue.sliding(options.bufferSize ?? 16);
default:
return Queue.dropping(options?.bufferSize ?? 16);
}
};
/** @internal */
export const asyncPush = (register, options) => Effect.acquireRelease(queueFromBufferOptionsPush(options), Queue.shutdown).pipe(Effect.tap(queue => FiberRef.getWith(FiberRef.currentScheduler, scheduler => register(emit.makePush(queue, scheduler)))), Effect.map(queue => {
const loop = core.flatMap(Queue.take(queue), item => Exit.isExit(item) ? Exit.isSuccess(item) ? core.void : core.failCause(item.cause) : channel.zipRight(core.write(Chunk.unsafeFromArray(item)), loop));
return loop;
}), channel.unwrapScoped, fromChannel);
/** @internal */
export const asyncScoped = (register, bufferSize) => pipe(Effect.acquireRelease(queueFromBufferOptions(bufferSize), queue => Queue.shutdown(queue)), Effect.flatMap(output => pipe(Effect.runtime(), Effect.flatMap(runtime => pipe(register(emit.make(k => pipe(InternalTake.fromPull(k), Effect.flatMap(take => Queue.offer(output, take)), Effect.asVoid, Runtime.runPromiseExit(runtime)).then(exit => {
if (Exit.isFailure(exit)) {
if (!Cause.isInterrupted(exit.cause)) {
throw Cause.squash(exit.cause);
}
}
}))), Effect.zipRight(Ref.make(false)), Effect.flatMap(ref => pipe(Ref.get(ref), Effect.map(isDone => isDone ? pull.end() : pipe(Queue.take(output), Effect.flatMap(InternalTake.done), Effect.onError(() => pipe(Ref.set(ref, true), Effect.zipRight(Queue.shutdown(output)))))))))))), scoped, flatMap(repeatEffectChunkOption));
/** @internal */
export const branchAfter = /*#__PURE__*/dual(3, (self, n, f) => suspend(() => {
const buffering = acc => core.readWith({
onInput: input => {
const nextSize = acc.length + input.length;
if (nextSize >= n) {
const [b1, b2] = pipe(input, Chunk.splitAt(n - acc.length));
return running(pipe(acc, Chunk.appendAll(b1)), b2);
}
return buffering(pipe(acc, Chunk.appendAll(input)));
},
onFailure: core.fail,
onDone: () => running(acc, Chunk.empty())
});
const running = (prefix, leftover) => core.pipeTo(channel.zipRight(core.write(leftover), channel.identityChannel()), toChannel(f(prefix)));
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(buffering(Chunk.empty()))));
}));
/** @internal */
export const broadcast = /*#__PURE__*/dual(3, (self, n, maximumLag) => pipe(self, broadcastedQueues(n, maximumLag), Effect.map(tuple => tuple.map(queue => flattenTake(fromQueue(queue, {
shutdown: true
}))))));
/** @internal */
export const broadcastDynamic = /*#__PURE__*/dual(2, (self, maximumLag) => Effect.map(toPubSub(self, maximumLag), pubsub => flattenTake(fromPubSub(pubsub))));
export const share = /*#__PURE__*/dual(2, (self, options) => Effect.map(RcRef.make({
acquire: broadcastDynamic(self, options),
idleTimeToLive: options.idleTimeToLive
}), rcRef => unwrapScoped(RcRef.get(rcRef))));
/** @internal */
export const broadcastedQueues = /*#__PURE__*/dual(3, (self, n, maximumLag) => Effect.flatMap(pubsubFromOptions(maximumLag), pubsub => pipe(Effect.all(Array.from({
length: n
}, () => PubSub.subscribe(pubsub))), Effect.tap(() => Effect.forkScoped(runIntoPubSubScoped(self, pubsub))))));
/** @internal */
export const broadcastedQueuesDynamic = /*#__PURE__*/dual(2, (self, maximumLag) => Effect.map(toPubSub(self, maximumLag), PubSub.subscribe));
/** @internal */
export const buffer = /*#__PURE__*/dual(2, (self, options) => {
if (options.capacity === "unbounded") {
return bufferUnbounded(self);
} else if (options.strategy === "dropping") {
return bufferDropping(self, options.capacity);
} else if (options.strategy === "sliding") {
return bufferSliding(self, options.capacity);
}
const queue = toQueueOfElements(self, options);
return new StreamImpl(channel.unwrapScoped(Effect.map(queue, queue => {
const process = pipe(core.fromEffect(Queue.take(queue)), core.flatMap(Exit.match({
onFailure: cause => pipe(Cause.flipCauseOption(cause), Option.match({
onNone: () => core.void,
onSome: core.failCause
})),
onSuccess: value => core.flatMap(core.write(Chunk.of(value)), () => process)
})));
return process;
})));
});
/** @internal */
export const bufferChunks = /*#__PURE__*/dual(2, (self, options) => {
if (options.strategy === "dropping") {
return bufferChunksDropping(self, options.capacity);
} else if (options.strategy === "sliding") {
return bufferChunksSliding(self, options.capacity);
}
const queue = toQueue(self, options);
return new StreamImpl(channel.unwrapScoped(Effect.map(queue, queue => {
const process = pipe(core.fromEffect(Queue.take(queue)), core.flatMap(InternalTake.match({
onEnd: () => core.void,
onFailure: core.failCause,
onSuccess: value => pipe(core.write(value), core.flatMap(() => process))
})));
return process;
})));
});
const bufferChunksDropping = /*#__PURE__*/dual(2, (self, capacity) => {
const queue = Effect.acquireRelease(Queue.dropping(capacity), queue => Queue.shutdown(queue));
return new StreamImpl(bufferSignal(queue, toChannel(self)));
});
const bufferChunksSliding = /*#__PURE__*/dual(2, (self, capacity) => {
const queue = Effect.acquireRelease(Queue.sliding(capacity), queue => Queue.shutdown(queue));
return new StreamImpl(bufferSignal(queue, toChannel(self)));
});
const bufferDropping = /*#__PURE__*/dual(2, (self, capacity) => {
const queue = Effect.acquireRelease(Queue.dropping(capacity), queue => Queue.shutdown(queue));
return new StreamImpl(bufferSignal(queue, toChannel(rechunk(1)(self))));
});
const bufferSliding = /*#__PURE__*/dual(2, (self, capacity) => {
const queue = Effect.acquireRelease(Queue.sliding(capacity), queue => Queue.shutdown(queue));
return new StreamImpl(bufferSignal(queue, toChannel(pipe(self, rechunk(1)))));
});
const bufferUnbounded = self => {
const queue = toQueue(self, {
strategy: "unbounded"
});
return new StreamImpl(channel.unwrapScoped(Effect.map(queue, queue => {
const process = pipe(core.fromEffect(Queue.take(queue)), core.flatMap(InternalTake.match({
onEnd: () => core.void,
onFailure: core.failCause,
onSuccess: value => core.flatMap(core.write(value), () => process)
})));
return process;
})));
};
const bufferSignal = (scoped, bufferChannel) => {
const producer = (queue, ref) => {
const terminate = take => pipe(Ref.get(ref), Effect.tap(Deferred.await), Effect.zipRight(Deferred.make()), Effect.flatMap(deferred => pipe(Queue.offer(queue, [take, deferred]), Effect.zipRight(Ref.set(ref, deferred)), Effect.zipRight(Deferred.await(deferred)))), Effect.asVoid, core.fromEffect);
return core.readWithCause({
onInput: input => pipe(Deferred.make(), Effect.flatMap(deferred => pipe(Queue.offer(queue, [InternalTake.chunk(input), deferred]), Effect.flatMap(added => pipe(Ref.set(ref, deferred), Effect.when(() => added))))), Effect.asVoid, core.fromEffect, core.flatMap(() => producer(queue, ref))),
onFailure: error => terminate(InternalTake.failCause(error)),
onDone: () => terminate(InternalTake.end)
});
};
const consumer = queue => {
const process = pipe(core.fromEffect(Queue.take(queue)), core.flatMap(([take, deferred]) => channel.zipRight(core.fromEffect(Deferred.succeed(deferred, void 0)), InternalTake.match(take, {
onEnd: () => core.void,
onFailure: core.failCause,
onSuccess: value => pipe(core.write(value), core.flatMap(() => process))
}))));
return process;
};
return channel.unwrapScoped(pipe(scoped, Effect.flatMap(queue => pipe(Deferred.make(), Effect.tap(start => Deferred.succeed(start, void 0)), Effect.flatMap(start => pipe(Ref.make(start), Effect.flatMap(ref => pipe(bufferChannel, core.pipeTo(producer(queue, ref)), channel.runScoped, Effect.forkScoped)), Effect.as(consumer(queue))))))));
};
/** @internal */
export const catchAll = /*#__PURE__*/dual(2, (self, f) => catchAllCause(self, cause => Either.match(Cause.failureOrCause(cause), {
onLeft: f,
onRight: failCause
})));
/** @internal */
export const catchAllCause = /*#__PURE__*/dual(2, (self, f) => new StreamImpl(pipe(toChannel(self), core.catchAllCause(cause => toChannel(f(cause))))));
/** @internal */
export const catchSome = /*#__PURE__*/dual(2, (self, pf) => pipe(self, catchAll(error => pipe(pf(error), Option.getOrElse(() => fail(error))))));
/** @internal */
export const catchSomeCause = /*#__PURE__*/dual(2, (self, pf) => pipe(self, catchAllCause(cause => pipe(pf(cause), Option.getOrElse(() => failCause(cause))))));
/* @internal */
export const catchTag = /*#__PURE__*/dual(3, (self, k, f) => catchAll(self, e => {
if ("_tag" in e && e["_tag"] === k) {
return f(e);
}
return fail(e);
}));
/** @internal */
export const catchTags = /*#__PURE__*/dual(2, (self, cases) => catchAll(self, e => {
const keys = Object.keys(cases);
if ("_tag" in e && keys.includes(e["_tag"])) {
return cases[e["_tag"]](e);
}
return fail(e);
}));
/** @internal */
export const changes = self => pipe(self, changesWith((x, y) => Equal.equals(y)(x)));
/** @internal */
export const changesWith = /*#__PURE__*/dual(2, (self, f) => {
const writer = last => core.readWithCause({
onInput: input => {
const [newLast, newChunk] = Chunk.reduce(input, [last, Chunk.empty()], ([option, outputs], output) => {
if (Option.isSome(option) && f(option.value, output)) {
return [Option.some(output), outputs];
}
return [Option.some(output), pipe(outputs, Chunk.append(output))];
});
return core.flatMap(core.write(newChunk), () => writer(newLast));
},
onFailure: core.failCause,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(writer(Option.none()))));
});
/** @internal */
export const changesWithEffect = /*#__PURE__*/dual(2, (self, f) => {
const writer = last => core.readWithCause({
onInput: input => pipe(input, Effect.reduce([last, Chunk.empty()], ([option, outputs], output) => {
if (Option.isSome(option)) {
return pipe(f(option.value, output), Effect.map(bool => bool ? [Option.some(output), outputs] : [Option.some(output), pipe(outputs, Chunk.append(output))]));
}
return Effect.succeed([Option.some(output), pipe(outputs, Chunk.append(output))]);
}), core.fromEffect, core.flatMap(([newLast, newChunk]) => pipe(core.write(newChunk), core.flatMap(() => writer(newLast))))),
onFailure: core.failCause,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(writer(Option.none()))));
});
/** @internal */
export const chunks = self => pipe(self, mapChunks(Chunk.of));
/** @internal */
export const chunksWith = /*#__PURE__*/dual(2, (self, f) => flattenChunks(f(chunks(self))));
const unsome = effect => Effect.catchAll(Effect.asSome(effect), o => o._tag === "None" ? Effect.succeedNone : Effect.fail(o.value));
/** @internal */
export const combine = /*#__PURE__*/dual(4, (self, that, s, f) => {
function producer(handoff, latch) {
return core.fromEffect(Handoff.take(latch)).pipe(channel.zipRight(core.readWithCause({
onInput: input => core.flatMap(core.fromEffect(Handoff.offer(handoff, Exit.succeed(input))), () => producer(handoff, latch)),
onFailure: cause => core.fromEffect(Handoff.offer(handoff, Exit.failCause(pipe(cause, Cause.map(Option.some))))),
onDone: () => core.flatMap(core.fromEffect(Handoff.offer(handoff, Exit.fail(Option.none()))), () => producer(handoff, latch))
})));
}
return new StreamImpl(channel.unwrapScopedWith(scope => Effect.all([Handoff.make(), Handoff.make(), Handoff.make(), Handoff.make()]).pipe(Effect.tap(([left, _, latchL]) => toChannel(self).pipe(channel.concatMap(channel.writeChunk), core.pipeTo(producer(left, latchL)), channelExecutor.runIn(scope), Effect.forkIn(scope))), Effect.tap(([, right, _, rightL]) => toChannel(that).pipe(channel.concatMap(channel.writeChunk), core.pipeTo(producer(right, rightL)), channelExecutor.runIn(scope), Effect.forkIn(scope))), Effect.map(([left, right, latchL, latchR]) => {
const pullLeft = Handoff.offer(latchL, void 0).pipe(Effect.zipRight(Handoff.take(left).pipe(Effect.flatMap(identity))));
const pullRight = Handoff.offer(latchR, void 0).pipe(Effect.zipRight(Handoff.take(right).pipe(Effect.flatMap(identity))));
return toChannel(unfoldEffect(s, s => Effect.flatMap(f(s, pullLeft, pullRight), unsome)));
}))));
});
/** @internal */
export const combineChunks = /*#__PURE__*/dual(4, (self, that, s, f) => {
const producer = (handoff, latch) => channel.zipRight(core.fromEffect(Handoff.take(latch)), core.readWithCause({
onInput: input => core.flatMap(core.fromEffect(pipe(handoff, Handoff.offer(InternalTake.chunk(input)))), () => producer(handoff, latch)),
onFailure: cause => core.fromEffect(Handoff.offer(handoff, InternalTake.failCause(cause))),
onDone: () => core.fromEffect(Handoff.offer(handoff, InternalTake.end))
}));
return new StreamImpl(channel.unwrapScopedWith(scope => Effect.all([Handoff.make(), Handoff.make(), Handoff.make(), Handoff.make()]).pipe(Effect.tap(([left, _, latchL]) => core.pipeTo(toChannel(self), producer(left, latchL)).pipe(channelExecutor.runIn(scope), Effect.forkIn(scope))), Effect.tap(([_, right, __, latchR]) => core.pipeTo(toChannel(that), producer(right, latchR)).pipe(channelExecutor.runIn(scope), Effect.forkIn(scope))), Effect.map(([left, right, latchL, latchR]) => {
const pullLeft = Handoff.offer(latchL, void 0).pipe(Effect.zipRight(Handoff.take(left).pipe(Effect.flatMap(InternalTake.done))));
const pullRight = Handoff.offer(latchR, void 0).pipe(Effect.zipRight(Handoff.take(right).pipe(Effect.flatMap(InternalTake.done))));
return toChannel(unfoldChunkEffect(s, s => Effect.flatMap(f(s, pullLeft, pullRight), unsome)));
}))));
});
/** @internal */
export const concat = /*#__PURE__*/dual(2, (self, that) => new StreamImpl(pipe(toChannel(self), channel.zipRight(toChannel(that)))));
/** @internal */
export const concatAll = streams => suspend(() => pipe(streams, Chunk.reduce(empty, (x, y) => concat(y)(x))));
/** @internal */
export const cross = /*#__PURE__*/dual(2, (left, right) => pipe(left, crossWith(right, (a, a2) => [a, a2])));
/** @internal */
export const crossLeft = /*#__PURE__*/dual(2, (left, right) => pipe(left, crossWith(right, (a, _) => a)));
/** @internal */
export const crossRight = /*#__PURE__*/dual(2, (left, right) => flatMap(left, () => right));
/** @internal */
export const crossWith = /*#__PURE__*/dual(3, (left, right, f) => pipe(left, flatMap(a => pipe(right, map(b => f(a, b))))));
/** @internal */
export const debounce = /*#__PURE__*/dual(2, (self, duration) => unwrapScopedWith(scope => Effect.gen(function* () {
const handoff = yield* Handoff.make();
function enqueue(last) {
return Clock.sleep(duration).pipe(Effect.as(last), Effect.forkIn(scope), Effect.map(fiber => consumer(DebounceState.previous(fiber))));
}
const producer = core.readWithCause({
onInput: input => Option.match(Chunk.last(input), {
onNone: () => producer,
onSome: elem => core.fromEffect(Handoff.offer(handoff, HandoffSignal.emit(Chunk.of(elem)))).pipe(core.flatMap(() => producer))
}),
onFailure: cause => core.fromEffect(Handoff.offer(handoff, HandoffSignal.halt(cause))),
onDone: () => core.fromEffect(Handoff.offer(handoff, HandoffSignal.end(SinkEndReason.UpstreamEnd)))
});
function consumer(state) {
switch (state._tag) {
case DebounceState.OP_NOT_STARTED:
{
return channel.unwrap(Handoff.take(handoff).pipe(Effect.map(signal => {
switch (signal._tag) {
case HandoffSignal.OP_EMIT:
{
return channel.unwrap(enqueue(signal.elements));
}
case HandoffSignal.OP_HALT:
{
return core.failCause(signal.cause);
}
case HandoffSignal.OP_END:
{
return core.void;
}
}
})));
}
case DebounceState.OP_PREVIOUS:
{
return channel.unwrap(Handoff.take(handoff).pipe(Effect.forkIn(scope), Effect.flatMap(handoffFiber => Effect.raceWith(Fiber.join(state.fiber), Fiber.join(handoffFiber), {
onSelfDone: (leftExit, current) => Exit.match(leftExit, {
onFailure: cause => Fiber.interrupt(current).pipe(Effect.as(core.failCause(cause))),
onSuccess: chunk => Fiber.interrupt(current).pipe(Effect.zipRight(Effect.succeed(core.write(chunk).pipe(core.flatMap(() => consumer(DebounceState.current(handoffFiber)))))))
}),
onOtherDone: (rightExit, previous) => Exit.match(rightExit, {
onFailure: cause => Fiber.interrupt(previous).pipe(Effect.as(core.failCause(cause))),
onSuccess: signal => {
switch (signal._tag) {
case HandoffSignal.OP_EMIT:
{
return Fiber.interrupt(previous).pipe(Effect.zipRight(enqueue(signal.elements)));
}
case HandoffSignal.OP_HALT:
{
return Fiber.interrupt(previous).pipe(Effect.as(core.failCause(signal.cause)));
}
case HandoffSignal.OP_END:
{
return Fiber.join(previous).pipe(Effect.map(chunk => core.write(chunk).pipe(channel.zipRight(core.void))));
}
}
}
})
}))));
}
case DebounceState.OP_CURRENT:
{
return channel.unwrap(Fiber.join(state.fiber).pipe(Effect.map(signal => {
switch (signal._tag) {
case HandoffSignal.OP_EMIT:
{
return channel.unwrap(enqueue(signal.elements));
}
case HandoffSignal.OP_HALT:
{
return core.failCause(signal.cause);
}
case HandoffSignal.OP_END:
{
return core.void;
}
}
})));
}
}
}
return scopedWith(scope => core.pipeTo(toChannel(self), producer).pipe(channelExecutor.runIn(scope), Effect.forkIn(scope))).pipe(crossRight(new StreamImpl(consumer(DebounceState.notStarted))));
})));
/** @internal */
export const die = defect => fromEffect(Effect.die(defect));
/** @internal */
export const dieSync = evaluate => fromEffect(Effect.dieSync(evaluate));
/** @internal */
export const dieMessage = message => fromEffect(Effect.dieMessage(message));
/** @internal */
export const distributedWith = /*#__PURE__*/dual(2, (self, options) => pipe(Deferred.make(), Effect.flatMap(deferred => pipe(self, distributedWithDynamic({
maximumLag: options.maximumLag,
decide: a => Effect.flatMap(Deferred.await(deferred), f => f(a))
}), Effect.flatMap(next => pipe(Effect.all(Chunk.map(Chunk.range(0, options.size - 1), id => Effect.map(next, ([key, queue]) => [[key, id], queue]))), Effect.map(Chunk.unsafeFromArray), Effect.flatMap(entries => {
const [mappings, queues] = Chunk.reduceRight(entries, [new Map(), Chunk.empty()], ([mappings, queues], [mapping, queue]) => [mappings.set(mapping[0], mapping[1]), pipe(queues, Chunk.prepend(queue))]);
return pipe(Deferred.succeed(deferred, a => Effect.map(options.decide(a), f => key => pipe(f(mappings.get(key))))), Effect.as(Array.from(queues)));
})))))));
/** @internal */
const distributedWithDynamicId = {
ref: 0
};
const newDistributedWithDynamicId = () => {
const current = distributedWithDynamicId.ref;
distributedWithDynamicId.ref = current + 1;
return current;
};
/** @internal */
export const distributedWithDynamic = /*#__PURE__*/dual(2, (self, options) => distributedWithDynamicCallback(self, options.maximumLag, options.decide, () => Effect.void));
/** @internal */
export const distributedWithDynamicCallback = /*#__PURE__*/dual(4, (self, maximumLag, decide, done) => pipe(Effect.acquireRelease(Ref.make(new Map()), (ref, _) => pipe(Ref.get(ref), Effect.flatMap(queues => pipe(queues.values(), Effect.forEach(Queue.shutdown))))), Effect.flatMap(queuesRef => Effect.gen(function* () {
const offer = a => pipe(decide(a), Effect.flatMap(shouldProcess => pipe(Ref.get(queuesRef), Effect.flatMap(queues => pipe(queues.entries(), Effect.reduce(Chunk.empty(), (acc, [id, queue]) => {
if (shouldProcess(id)) {
return pipe(Queue.offer(queue, Exit.succeed(a)), Effect.matchCauseEffect({
onFailure: cause =>
// Ignore all downstream queues that were shut
// down and remove them later
Cause.isInterrupted(cause) ? Effect.succeed(pipe(acc, Chunk.prepend(id))) : Effect.failCause(cause),
onSuccess: () => Effect.succeed(acc)
}));
}
return Effect.succeed(acc);
}), Effect.flatMap(ids => {
if (Chunk.isNonEmpty(ids)) {
return pipe(Ref.update(queuesRef, map => {
for (const id of ids) {
map.delete(id);
}
return map;
}));
}
return Effect.void;
}))))), Effect.asVoid);
const queuesLock = yield* Effect.makeSemaphore(1);
const newQueue = yield* Ref.make(pipe(Queue.bounded(maximumLag), Effect.flatMap(queue => {
const id = newDistributedWithDynamicId();
return pipe(Ref.update(queuesRef, map => map.set(id, queue)), Effect.as([id, queue]));
})));
const finalize = endTake =>
// Make sure that no queues are currently being added
queuesLock.withPermits(1)(pipe(Ref.set(newQueue, pipe(
// All newly created queues should end immediately
Queue.bounded(1), Effect.tap(queue => Queue.offer(queue, endTake)), Effect.flatMap(queue => {
const id = newDistributedWithDynamicId();
return pipe(Ref.update(queuesRef, map => map.set(id, queue)), Effect.as(Tuple.make(id, queue)));
}))), Effect.zipRight(pipe(Ref.get(queuesRef), Effect.flatMap(map => pipe(Chunk.fromIterable(map.values()), Effect.forEach(queue => pipe(Queue.offer(queue, endTake), Effect.catchSomeCause(cause => Cause.isInterrupted(cause) ? Option.some(Effect.void) : Option.none()))))))), Effect.zipRight(done(endTake)), Effect.asVoid));
yield* pipe(self, runForEachScoped(offer), Effect.matchCauseEffect({
onFailure: cause => finalize(Exit.failCause(pipe(cause, Cause.map(Option.some)))),
onSuccess: () => finalize(Exit.fail(Option.none()))
}), Effect.forkScoped);
return queuesLock.withPermits(1)(Effect.flatten(Ref.get(newQueue)));
}))));
/** @internal */
export const drain = self => new StreamImpl(channel.drain(toChannel(self)));
/** @internal */
export const drainFork = /*#__PURE__*/dual(2, (self, that) => fromEffect(Deferred.make()).pipe(flatMap(backgroundDied => scopedWith(scope => toChannel(that).pipe(channel.drain, channelExecutor.runIn(scope), Effect.catchAllCause(cause => Deferred.failCause(backgroundDied, cause)), Effect.forkIn(scope))).pipe(crossRight(interruptWhenDeferred(self, backgroundDied))))));
/** @internal */
export const drop = /*#__PURE__*/dual(2, (self, n) => {
const loop = r => core.readWith({
onInput: input => {
const dropped = pipe(input, Chunk.drop(r));
const leftover = Math.max(0, r - input.length);
const more = Chunk.isEmpty(input) || leftover > 0;
if (more) {
return loop(leftover);
}
return pipe(core.write(dropped), channel.zipRight(channel.identityChannel()));
},
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(loop(n))));
});
/** @internal */
export const dropRight = /*#__PURE__*/dual(2, (self, n) => {
if (n <= 0) {
return identityStream();
}
return suspend(() => {
const queue = new RingBuffer(n);
const reader = core.readWith({
onInput: input => {
const outputs = pipe(input, Chunk.filterMap(elem => {
const head = queue.head();
queue.put(elem);
return head;
}));
return pipe(core.write(outputs), core.flatMap(() => reader));
},
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(reader)));
});
});
/** @internal */
export const dropUntil = /*#__PURE__*/dual(2, (self, predicate) => drop(dropWhile(self, a => !predicate(a)), 1));
/** @internal */
export const dropUntilEffect = /*#__PURE__*/dual(2, (self, predicate) => {
const loop = core.readWith({
onInput: input => pipe(Effect.dropUntil(input, predicate), Effect.map(Chunk.unsafeFromArray), Effect.map(leftover => {
const more = Chunk.isEmpty(leftover);
if (more) {
return core.suspend(() => loop);
}
return pipe(core.write(leftover), channel.zipRight(channel.identityChannel()));
}), channel.unwrap),
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(loop)));
});
/** @internal */
export const dropWhile = /*#__PURE__*/dual(2, (self, predicate) => {
const loop = core.readWith({
onInput: input => {
const output = Chunk.dropWhile(input, predicate);
if (Chunk.isEmpty(output)) {
return core.suspend(() => loop);
}
return channel.zipRight(core.write(output), channel.identityChannel());
},
onFailure: core.fail,
onDone: core.succeedNow
});
return new StreamImpl(channel.pipeToOrFail(toChannel(self), loop));
});
/** @internal */
export const dropWhileEffect = /*#__PURE__*/dual(2, (self, predicate) => {
const loop = core.readWith({
onInput: input => pipe(Effect.dropWhile(input, predicate), Effect.map(Chunk.unsafeFromArray), Effect.map(leftover => {
const more = Chunk.isEmpty(leftover);
if (more) {
return core.suspend(() => loop);
}
return channel.zipRight(core.write(leftover), channel.identityChannel());
}), channel.unwrap),
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(channel.pipeToOrFail(toChannel(self), loop));
});
/** @internal */
export const either = self => pipe(self, map(Either.right), catchAll(error => make(Either.left(error))));
/** @internal */
export const empty = /*#__PURE__*/new StreamImpl(core.void);
/** @internal */
export const ensuring = /*#__PURE__*/dual(2, (self, finalizer) => new StreamImpl(pipe(toChannel(self), channel.ensuring(finalizer))));
/** @internal */
export const ensuringWith = /*#__PURE__*/dual(2, (self, finalizer) => new StreamImpl(core.ensuringWith(toChannel(self), finalizer)));
/** @internal */
export const context = () => fromEffect(Effect.context());
/** @internal */
export const contextWith = f => pipe(context(), map(f));
/** @internal */
export const contextWithEffect = f => pipe(context(), mapEffectSequential(f));
/** @internal */
export const contextWithStream = f => pipe(context(), flatMap(f));
/** @internal */
export const execute = effect => drain(fromEffect(effect));
/** @internal */
export const fail = error => fromEffectOption(Effect.fail(Option.some(error)));
/** @internal */
export const failSync = evaluate => fromEffectOption(Effect.failSync(() => Option.some(evaluate())));
/** @internal */
export const failCause = cause => fromEffect(Effect.failCause(cause));
/** @internal */
export const failCauseSync = evaluate => fromEffect(Effect.failCauseSync(evaluate));
/** @internal */
export const filter = /*#__PURE__*/dual(2, (self, predicate) => mapChunks(self, Chunk.filter(predicate)));
/** @internal */
export const filterEffect = /*#__PURE__*/dual(2, (self, f) => {
const loop = iterator => {
const next = iterator.next();
if (next.done) {
return core.readWithCause({
onInput: input => loop(input[Symbol.iterator]()),
onFailure: core.failCause,
onDone: core.succeed
});
} else {
return pipe(f(next.value), Effect.map(bool => bool ? pipe(core.write(Chunk.of(next.value)), core.flatMap(() => loop(iterator))) : loop(iterator)), channel.unwrap);
}
};
return new StreamImpl(core.suspend(() => pipe(toChannel(self), core.pipeTo(loop(Chunk.empty()[Symbol.iterator]())))));
});
/** @internal */
export const filterMap = /*#__PURE__*/dual(2, (self, pf) => mapChunks(self, Chunk.filterMap(pf)));
/** @internal */
export const filterMapEffect = /*#__PURE__*/dual(2, (self, pf) => suspend(() => {
const loop = iterator => {
const next = iterator.next();
if (next.done) {
return core.readWithCause({
onInput: input => loop(input[Symbol.iterator]()),
onFailure: core.failCause,
onDone: core.succeed
});
} else {
return pipe(pf(next.value), Option.match({
onNone: () => Effect.sync(() => loop(iterator)),
onSome: Effect.map(a2 => core.flatMap(core.write(Chunk.of(a2)), () => loop(iterator)))
}), channel.unwrap);
}
};
return new StreamImpl(pipe(toChannel(self), core.pipeTo(loop(Chunk.empty()[Symbol.iterator]()))));
}));
/** @internal */
export const filterMapWhile = /*#__PURE__*/dual(2, (self, pf) => {
const loop = core.readWith({
onInput: input => {
const mapped = Chunk.filterMapWhile(input, pf);
if (mapped.length === input.length) {
return pipe(core.write(mapped), core.flatMap(() => loop));
}
return core.write(mapped);
},
onFailure: core.fail,
onDone: core.succeed
});
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(loop)));
});
/** @internal */
export const filterMapWhileEffect = /*#__PURE__*/dual(2, (self, pf) => suspend(() => {
const loop = iterator => {
const next = iterator.next();
if (next.done) {
return core.readWithCause({
onInput: input => loop(input[Symbol.iterator]()),
onFailure: core.failCause,
onDone: core.succeed
});
} else {
return channel.unwrap(Option.match(pf(next.value), {
onNone: () => Effect.succeed(core.void),
onSome: Effect.map(a2 => core.flatMap(core.write(Chunk.of(a2)), () => loop(iterator)))
}));
}
};
return new StreamImpl(pipe(toChannel(self), channel.pipeToOrFail(loop(Chunk.empty()[Symbol.iterator]()))));
}));
/** @internal */
export const finalizer = finalizer => acquireRelease(Effect.void, () => finalizer);
/** @internal */
export const find = /*#__PURE__*/dual(2, (self, predicate) => {
const loop = core.readWith({
onInput: input => Option.match(Chunk.findFirst(input, predicate), {
onNone: () => loop,
onSome: n => core.write(Chunk.of(n))
}),
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(loop)));
});
/** @internal */
export const findEffect = /*#__PURE__*/dual(2, (self, predicate) => {
const loop = core.readWith({
onInput: input => pipe(Effect.findFirst(input, predicate), Effect.map(Option.match({
onNone: () => loop,
onSome: n => core.write(Chunk.of(n))
})), channel.unwrap),
onFailure: core.fail,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(loop)));
});
/** @internal */
export const flatMap = /*#__PURE__*/dual(args => isStream(args[0]), (self, f, options) => {
const bufferSize = options?.bufferSize ?? 16;
if (options?.switch) {
return matchConcurrency(options?.concurrency, () => flatMapParSwitchBuffer(self, 1, bufferSize, f), n => flatMapParSwitchBuffer(self, n, bufferSize, f));
}
return matchConcurrency(options?.concurrency, () => new StreamImpl(channel.concatMap(toChannel(self), as => pipe(as, Chunk.map(a => toChannel(f(a))), Chunk.reduce(core.void, (left, right) => pipe(left, channel.zipRight(right)))))), _ => new StreamImpl(pipe(toChannel(self), channel.concatMap(channel.writeChunk), channel.mergeMap(out => toChannel(f(out)), options))));
});
/** @internal */
export const matchConcurrency = (concurrency, sequential, bounded) => {
switch (concurrency) {
case undefined:
return sequential();
case "unbounded":
return bounded(Number.MAX_SAFE_INTEGER);
default:
return concurrency > 1 ? bounded(concurrency) : sequential();
}
};
const flatMapParSwitchBuffer = /*#__PURE__*/dual(4, (self, n, bufferSize, f) => new StreamImpl(pipe(toChannel(self), channel.concatMap(channel.writeChunk), channel.mergeMap(out => toChannel(f(out)), {
concurrency: n,
mergeStrategy: MergeStrategy.BufferSliding(),
bufferSize
}))));
/** @internal */
export const flatten = /*#__PURE__*/dual(args => isStream(args[0]), (self, options) => flatMap(self, identity, options));
/** @internal */
export const flattenChunks = self => {
const flatten = core.readWithCause({
onInput: chunks => core.flatMap(channel.writeChunk(chunks), () => flatten),
onFailure: core.failCause,
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(flatten)));
};
/** @internal */
export const flattenEffect = /*#__PURE__*/dual(args => isStream(args[0]), (self, options) => options?.unordered ? flatMap(self, a => fromEffect(a), {
concurrency: options.concurrency
}) : matchConcurrency(options?.concurrency, () => mapEffectSequential(self, identity), n => new StreamImpl(pipe(toChannel(self), channel.concatMap(channel.writeChunk), channel.mapOutEffectPar(identity, n), channel.mapOut(Chunk.of)))));
/** @internal */
export const flattenExitOption = self => {
const processChunk = (chunk, cont) => {
const [toEmit, rest] = pipe(chunk, Chunk.splitWhere(exit => !Exit.isSuccess(exit)));
const next = pipe(Chunk.head(rest), Option.match({
onNone: () => cont,
onSome: Exit.match({
onFailure: cause => Option.match(Cause.flipCauseOption(cause), {
onNone: () => core.void,
onSome: core.failCause
}),
onSuccess: () => core.void
})
}));
return pipe(core.write(pipe(toEmit, Chunk.filterMap(exit => Exit.isSuccess(exit) ? Option.some(exit.value) : Option.none()))), core.flatMap(() => next));
};
const process = core.readWithCause({
onInput: chunk => processChunk(chunk, process),
onFailure: cause => core.failCause(cause),
onDone: () => core.void
});
return new StreamImpl(pipe(toChannel(self), core.pipeTo(process)));
};
/** @internal */
export const flattenIterables = self => pipe(self, map(Chunk.fromIterable), flattenChunks);
/** @internal */
export const flattenTake = self => flattenChunks(flattenExitOption(pipe(self, map(take => take.exit))));
/** @internal */
export const forever = self => new StreamImpl(channel.repeated(toChannel(self)));
/** @internal */
export const fromAsyncIterable = (iterable, onError) => pipe(Effect.acquireRelease(Effect.sync(() => iterable[Symbol.asyncIterator]()), iterator => iterator.return ? Effect.promise(async () => iterator.return()) : Effect.void), Effect.map(iterator => repeatEffectOption(pipe(Effect.tryPromise({
try: async () => iterator.next(),
catch: reason => Option.some(onError(reason))
}), Effect.flatMap(result => result.done ? Effect.fail(Option.none()) : Effect.succeed(result.value))))), unwrapScoped);
/** @internal */
export const fromChannel = channel => new StreamImpl(channel);
/** @internal */
export const toChannel = stream => {
if ("channel" in stream) {
return stream.channel;
} else if (Effect.isEffect(stream)) {
return toChannel(fromEffect(stream));
} else {
throw new TypeError(`Expected a Stream.`);
}
};
/** @internal */
export const fromChunk = chunk => new StreamImpl(Chunk.isEmpty(chunk) ? core.void : core.write(chunk));
/** @internal */
export const fromChunkPubSub = (pubsub, options) => {
if (options?.scoped) {
const effect = Effect.map(PubSub.subscribe(pubsub), fromChunkQueue);
return options.shutdown ? Effect.map(effect, ensuring(PubSub.shutdown(pubsub))) : effect;
}
const stream = flatMap(scoped(PubSub.subscribe(pubsub)), fromChunkQueue);
return options?.shutdown ? ensuring(stream, PubSub.shutdown(pubsub)) : stream;
};
/** @internal */
export const fromChunkQueue = (queue, options) => pipe(Queue.take(queue), Effect.catchAllCause(cause => pipe(Queue.isShutdown(queue), Effect.flatMap(isShutdown => isShutdown && Cause.isInterrupted(cause) ? pull.end() : pull.failCause(cause)))), repeatEffectChunkOption, options?.shutdown ? ensuring(Queue.shutdown(queue)) : identity);
/** @internal */
export const fromChunks = (...chunks) => pipe(fromIterable(chunks), flatMap(fromChunk));
/** @internal */
export const fromEffect = effect => pipe(effect, Effect.mapError(Option.some), fromEffectOption);
/** @internal */
export const fromEffectOption = effect => new StreamImpl(channel.unwrap(Effect.match(effect, {
onFailure: Option.match({
onNone: () => core.void,
onSome: core.fail
}),
onSuccess: a => core.write(Chunk.of(a))
})));
/** @internal */
export const fromPubSub = (pubsub, options) => {
const maxChunkSize = options?.maxChunkSize ?? DefaultChunkSize;
if (options?.scoped) {
const effect = Effect.map(PubSub.subscribe(pubsub), queue => fromQueue(queue, {
maxChunkSize,
shutdown: true
}));
return options.shutdown ? Effect.map(effect, ensuring(PubSub.shutdown(pubsub))) : effect;
}
const stream = flatMap(scoped(PubSub.subscribe(pubsub)), queue => fromQueue(queue, {
maxChunkSize
}));
return options?.shutdown ? ensuring(stream, PubSub.shutdown(pubsub)) : stream;
};
/** @internal */
export const fromTPubSub = pubsub => {
return unwrapScoped(Effect.map(TPubSub.subscribeScoped(pubsub), queue => fromTQueue(queue)));
};
/** @internal */
export const fromIterable = iterable => suspend(() => Chunk.isChunk(iterable) ? fromChu