UNPKG

veffect

Version:

powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha

968 lines 128 kB
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 { 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, isTagged } from "../Predicate.js"; import * as PubSub from "../PubSub.js"; import * as Queue from "../Queue.js"; import * as Ref from "../Ref.js"; import * as Runtime from "../Runtime.js"; import * as Schedule from "../Schedule.js"; import * as Scope from "../Scope.js"; import * as HaltStrategy from "../StreamHaltStrategy.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 singleProducerAsyncInput from "./channel/singleProducerAsyncInput.js"; import * as core from "./core-stream.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"; /** @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.unit }); 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 pipe(fromEffect(layer), 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.unit : 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, channelExecutor.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.unit), 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 unwrapScoped(pipe(self, toChannel, core.pipeTo(handoffProducer), channelExecutor.run, Effect.forkScoped, Effect.zipRight(pipe(handoffConsumer, channel.pipeToOrFail(_sink.toChannel(sink)), core.collectElements, channelExecutor.run, Effect.forkScoped, Effect.flatMap(sinkFiber => pipe(Effect.forkScoped(timeout(Option.none())), Effect.flatMap(scheduleFiber => pipe(Effect.scope, Effect.map(scope => new StreamImpl(scheduledAggregator(sinkFiber, scheduleFiber, scope))))))))))); })); }); /** @internal */ export const as = /*#__PURE__*/dual(2, (self, value) => map(self, () => value)); /** @internal */ export const _async = (register, outputBuffer = 16) => Effect.acquireRelease(Queue.bounded(outputBuffer), 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.asUnit, 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.unit, onSome: error => core.fail(error) }))), onSuccess: chunk => core.write(chunk).pipe(core.flatMap(() => loop)) }), channel.unwrap); return fromChannel(loop).pipe(ensuring(value ?? Effect.unit)); }))), unwrapScoped); /** @internal */ export const asyncEffect = (register, outputBuffer = 16) => pipe(Effect.acquireRelease(Queue.bounded(outputBuffer), 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.asUnit, 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.unit, onSome: core.fail }))), onSuccess: chunk => pipe(core.write(chunk), core.flatMap(() => loop)) }), channel.unwrap); return loop; }))))), channel.unwrapScoped, fromChannel); /** @internal */ export const asyncScoped = (register, outputBuffer = 16) => pipe(Effect.acquireRelease(Queue.bounded(outputBuffer), 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.asUnit, 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) => pipe(self, broadcastedQueuesDynamic(maximumLag), Effect.map(effect => flattenTake(flatMap(scoped(effect), fromQueue))))); /** @internal */ export const broadcastedQueues = /*#__PURE__*/dual(3, (self, n, maximumLag) => Effect.flatMap(PubSub.bounded(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.unit, 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.unit, 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.unit, 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.asUnit, 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.asUnit, 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.unit, 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)), channelExecutor.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.unit }); 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.unit }); 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) => { const producer = (handoff, latch) => pipe(core.fromEffect(Handoff.take(latch)), channel.zipRight(core.readWithCause({ onInput: input => core.flatMap(core.fromEffect(pipe(handoff, Handoff.offer(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.unwrapScoped(Effect.gen(function* ($) { const left = yield* $(Handoff.make()); const right = yield* $(Handoff.make()); const latchL = yield* $(Handoff.make()); const latchR = yield* $(Handoff.make()); yield* $(toChannel(self), channel.concatMap(channel.writeChunk), core.pipeTo(producer(left, latchL)), channelExecutor.runScoped, Effect.forkScoped); yield* $(toChannel(that), channel.concatMap(channel.writeChunk), core.pipeTo(producer(right, latchR)), channelExecutor.runScoped, Effect.forkScoped); const pullLeft = pipe(latchL, Handoff.offer(void 0), // TODO: remove Effect.zipRight(pipe(Handoff.take(left), Effect.flatMap(exit => Effect.suspend(() => exit))))); const pullRight = pipe(latchR, Handoff.offer(void 0), // TODO: remove Effect.zipRight(pipe(Handoff.take(right), Effect.flatMap(exit => Effect.suspend(() => exit))))); 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(pipe(Effect.all([Handoff.make(), Handoff.make(), Handoff.make(), Handoff.make()]), Effect.tap(([left, _, latchL]) => pipe(toChannel(self), core.pipeTo(producer(left, latchL)), channelExecutor.runScoped, Effect.forkScoped)), Effect.tap(([_, right, __, latchR]) => pipe(toChannel(that), core.pipeTo(producer(right, latchR)), channelExecutor.runScoped, Effect.forkScoped)), Effect.map(([left, right, latchL, latchR]) => { const pullLeft = pipe(latchL, Handoff.offer(void 0), Effect.zipRight(pipe(Handoff.take(left), Effect.flatMap(InternalTake.done)))); const pullRight = pipe(latchR, Handoff.offer(void 0), Effect.zipRight(pipe(Handoff.take(right), Effect.flatMap(InternalTake.done)))); return toChannel(unfoldChunkEffect(s, s => Effect.flatMap(f(s, pullLeft, pullRight), unsome))); }), channel.unwrapScoped)); }); /** @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, (self, that) => pipe(self, crossWith(that, (a, a2) => [a, a2]))); /** @internal */ export const crossLeft = /*#__PURE__*/dual(2, (self, that) => pipe(self, crossWith(that, (a, _) => a))); /** @internal */ export const crossRight = /*#__PURE__*/dual(2, (self, that) => flatMap(self, () => that)); /** @internal */ export const crossWith = /*#__PURE__*/dual(3, (self, that, f) => pipe(self, flatMap(a => pipe(that, map(b => f(a, b)))))); /** @internal */ export const debounce = /*#__PURE__*/dual(2, (self, duration) => pipe(singleProducerAsyncInput.make(), Effect.flatMap(input => Effect.transplant(grafter => pipe(Handoff.make(), Effect.map(handoff => { const enqueue = last => pipe(Clock.sleep(duration), Effect.as(last), Effect.fork, grafter, Effect.map(fiber => consumer(DebounceState.previous(fiber)))); const producer = core.readWithCause({ onInput: input => Option.match(Chunk.last(input), { onNone: () => producer, onSome: last => core.flatMap(core.fromEffect(Handoff.offer(handoff, HandoffSignal.emit(Chunk.of(last)))), () => producer) }), onFailure: cause => core.fromEffect(Handoff.offer(handoff, HandoffSignal.halt(cause))), onDone: () => core.fromEffect(Handoff.offer(handoff, HandoffSignal.end(SinkEndReason.UpstreamEnd))) }); const consumer = state => { switch (state._tag) { case DebounceState.OP_NOT_STARTED: { return pipe(Handoff.take(handoff), 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.unit; } } }), channel.unwrap); } case DebounceState.OP_PREVIOUS: { return channel.unwrap(Effect.raceWith(Fiber.join(state.fiber), Handoff.take(handoff), { onSelfDone: (leftExit, current) => Exit.match(leftExit, { onFailure: cause => pipe(Fiber.interrupt(current), Effect.as(core.failCause(cause))), onSuccess: chunk => Effect.succeed(pipe(core.write(chunk), core.flatMap(() => consumer(DebounceState.current(current))))) }), onOtherDone: (rightExit, previous) => Exit.match(rightExit, { onFailure: cause => pipe(Fiber.interrupt(previous), Effect.as(core.failCause(cause))), onSuccess: signal => { switch (signal._tag) { case HandoffSignal.OP_EMIT: { return pipe(Fiber.interrupt(previous), Effect.zipRight(enqueue(signal.elements))); } case HandoffSignal.OP_HALT: { return pipe(Fiber.interrupt(previous), Effect.as(core.failCause(signal.cause))); } case HandoffSignal.OP_END: { return pipe(Fiber.join(previous), Effect.map(chunk => pipe(core.write(chunk), channel.zipRight(core.unit)))); } } } }) })); } case DebounceState.OP_CURRENT: { return pipe(Fiber.join(state.fiber), 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.unit; } } }), channel.unwrap); } } }; const debounceChannel = pipe(channel.fromInput(input), core.pipeTo(producer), channelExecutor.run, Effect.forkScoped, Effect.as(pipe(consumer(DebounceState.notStarted), core.embedInput(input))), channel.unwrapScoped); return new StreamImpl(pipe(toChannel(self), core.pipeTo(debounceChannel))); })))), unwrap)); /** @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.unit)); /** @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.unit; }))))), Effect.asUnit); 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.unit) : Option.none()))))))), Effect.zipRight(done(endTake)), Effect.asUnit)); yield* $(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) => pipe(fromEffect(Deferred.make()), flatMap(backgroundDied => pipe(scoped(pipe(that, runForEachScoped(() => Effect.unit), Effect.catchAllCause(cause => Deferred.failCause(backgroundDied, cause)), Effect.forkScoped)), crossRight(pipe(self, interruptWhenDeferred(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.unit }); 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.unit }); 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.unit }); 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.unit }); 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( /*#__PURE__*/core.write( /*#__PURE__*/Chunk.empty())); /** @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.unit), 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.unit, () => 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.unit }); 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.unit }); 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.unit, (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.unit }); 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.unit, onSome: core.failCause }), onSuccess: () => core.unit }) })); 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.unit }); 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.unit), 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.unit : 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.unit, 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 fromIterable = iterable => suspend(() => Chunk.isChunk(iterable) ? fromChunk(iterable) : fromIteratorSucceed(iterable[Symbol.iterator]())); /** @internal */ export const fromIterableEffect = effect => pipe(effect, Effect.map(fromIterable), unwrap); /** @internal */ export const fromIteratorSucceed = (iterator, maxChunkSize = DefaultChunkSize) => { return pipe(Effect.sync(() => { let builder = []; const loop = iterator => pipe(Effect.sync(() => { let next = iterator.next(); if (maxChunkSize === 1) { if (next.done) { return core.unit; } return pipe(core.write(Chunk.of(next.value)), core.flatMap(() => loop(iterator))); } builder = []; let count = 0; while (next.done === false) { builder.push(next.value); count = count + 1; if (count >= maxChunkSize) { break; } next = iterator.next(); } if (count > 0) { return pipe(core.write(Chunk.unsafeFromArray(builder)), core.flatMap(() => loop(iterator))); } return core.unit; }), channel.unwrap); return new StreamImpl(loop(iterator)); }), unwrap); }; /** @internal */ export const fromPull = effect => pipe(effect, Effect.map(repeatEffectChunkOption), unwrapScoped); /** @internal */ export const fromQueue = (queue, options) => pipe(Queue.takeBetween(queue, 1, options?.maxChunkSize ?? DefaultChunkSize), 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 fromSchedule = schedule => pipe(Schedule.driver(schedule), Effect.map(driver => repeatEffectOption(driver