"use strict"
var __createBinding =
  (this && this.__createBinding) ||
  (Object.create
    ? function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        Object.defineProperty(o, k2, {
          enumerable: true,
          get: function () {
            return m[k]
          }
        })
      }
    : function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        o[k2] = m[k]
      })
var __setModuleDefault =
  (this && this.__setModuleDefault) ||
  (Object.create
    ? function (o, v) {
        Object.defineProperty(o, "default", { enumerable: true, value: v })
      }
    : function (o, v) {
        o["default"] = v
      })
var __importStar =
  (this && this.__importStar) ||
  function (mod) {
    if (mod && mod.__esModule) return mod
    var result = {}
    if (mod != null)
      for (var k in mod)
        if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
          __createBinding(result, mod, k)
    __setModuleDefault(result, mod)
    return result
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.concat =
  exports.concat_ =
  exports.combine =
  exports.collectWhileSuccess =
  exports.collectWhileRight =
  exports.collectWhileSome =
  exports.collectWhileM =
  exports.collectWhileM_ =
  exports.collectWhileLeft =
  exports.collectWhile =
  exports.collectWhile_ =
  exports.collectM =
  exports.collectM_ =
  exports.collectSuccess =
  exports.collectSome =
  exports.collectRight =
  exports.collectLeft =
  exports.collect =
  exports.collect_ =
  exports.chunks =
  exports.chunkN =
  exports.chunkN_ =
  exports.catchSomeCause =
  exports.catchSomeCause_ =
  exports.catchSome =
  exports.catchSome_ =
  exports.catchAllCause =
  exports.catchAllCause_ =
  exports.catchAll =
  exports.catchAll_ =
  exports.bufferUnbounded =
  exports.buffer =
  exports.buffer_ =
  exports.broadcastedQueuesDynamic =
  exports.broadcastedQueuesDynamic_ =
  exports.broadcastedQueues =
  exports.broadcastedQueues_ =
  exports.broadcastDynamic =
  exports.broadcastDynamic_ =
  exports.bimap =
  exports.bimap_ =
  exports.as =
  exports.as_ =
  exports.aggregateAsyncWithinEither =
  exports.aggregateAsyncWithinEither_ =
  exports.aggregateAsyncWithin =
  exports.aggregateAsyncWithin_ =
  exports.aggregateAsync =
  exports.aggregateAsync_ =
  exports.absolve =
    void 0
exports.filterM =
  exports.filterM_ =
  exports.runForEachWhileManaged =
  exports.runForEachWhileManaged_ =
  exports.runForEachWhile =
  exports.runForEachWhile_ =
  exports.runForEachManaged =
  exports.runForEachManaged_ =
  exports.runForEachChunkManaged =
  exports.runForEachChunkManaged_ =
  exports.runForEachChunk =
  exports.runForEachChunk_ =
  exports.runForEach =
  exports.runForEach_ =
  exports.forEach =
  exports.forEach_ =
  exports.runReduceWhileManagedM =
  exports.runReduceWhileManaged =
  exports.runReduceWhileManaged_ =
  exports.runReduceWhileM =
  exports.runReduceWhile =
  exports.runReduceManagedM =
  exports.runReduceManaged =
  exports.runReduceM =
  exports.runReduce =
  exports.filter =
  exports.filter_ =
  exports.ensuring =
  exports.ensuring_ =
  exports.either =
  exports.dropUntil =
  exports.dropUntil_ =
  exports.dropWhile =
  exports.dropWhile_ =
  exports.drop =
  exports.drop_ =
  exports.drainFork =
  exports.drainFork_ =
  exports.drain =
  exports.distributedWithDynamic =
  exports.distributedWithDynamic_ =
  exports.distributedWith =
  exports.distributedWith_ =
  exports.crossWith =
  exports.crossRight =
  exports.crossRight_ =
  exports.crossLeft =
  exports.crossLeft_ =
  exports.cross =
  exports.cross_ =
    void 0
exports.transduce =
  exports.transduce_ =
  exports.scheduleWith =
  exports.scheduleEither =
  exports.scheduleEither_ =
  exports.schedule =
  exports.schedule_ =
  exports.interruptWhenP =
  exports.interruptWhenP_ =
  exports.interruptWhen =
  exports.interruptWhen_ =
  exports.runManaged =
  exports.runManaged_ =
  exports.fromHub =
  exports.halt =
  exports.toQueueUnbounded =
  exports.toQueue =
  exports.toQueue_ =
  exports.unfoldM =
  exports.unfoldChunkM =
  exports.repeatEffectChunkOption =
  exports.fromQueue =
  exports.fromQueue_ =
  exports.toHub =
  exports.toHub_ =
  exports.DEFAULT_CHUNK_SIZE =
  exports.runIntoManaged =
  exports.runIntoManaged_ =
  exports.runIntoHubManaged =
  exports.runIntoHubManaged_ =
  exports.mapError =
  exports.mapError_ =
  exports.mapChunks =
  exports.mapChunks_ =
  exports.fromEffectOption =
  exports.fromEffect =
  exports.flattenTake =
  exports.flattenIterables =
  exports.flattenExitOption =
  exports.flattenExit =
  exports.flattenChunks =
  exports.fixed =
  exports.fixed_ =
  exports.filterNot =
  exports.filterNot_ =
    void 0
const tracing_1 = __importStar(require("../../../Tracing"))
const tracing_2 = __importStar(require("../../../Tracing"))
const fileName_1 = "(@effect-ts/system): _src/Experimental/Stream/_internal/api.ts"
const CS = __importStar(require("../../../Cause"))
const A = __importStar(require("../../../Collections/Immutable/Chunk"))
const HashMap = __importStar(require("../../../Collections/Immutable/HashMap"))
const L = __importStar(require("../../../Collections/Immutable/List"))
const Tp = __importStar(require("../../../Collections/Immutable/Tuple"))
const T = __importStar(require("../../../Effect"))
const E = __importStar(require("../../../Either"))
const Ex = __importStar(require("../../../Exit"))
const F = __importStar(require("../../../Fiber"))
const Function_1 = require("../../../Function")
const H = __importStar(require("../../../Hub"))
const M = __importStar(require("../../../Managed"))
const O = __importStar(require("../../../Option"))
const P = __importStar(require("../../../Promise"))
const Q = __importStar(require("../../../Queue"))
const Ref = __importStar(require("../../../Ref"))
const SC = __importStar(require("../../../Schedule"))
const SM = __importStar(require("../../../Semaphore"))
const AtomicBoolean_1 = require("../../../Support/AtomicBoolean")
const AtomicNumber_1 = require("../../../Support/AtomicNumber")
const AtomicReference_1 = require("../../../Support/AtomicReference")
const C = __importStar(require("../_internal/core"))
const CH = __importStar(require("../Channel"))
const SK = __importStar(require("../Sink"))
const BP = __importStar(require("./BufferedPull"))
const core_1 = require("./core")
const HO = __importStar(require("./Handoff"))
const Pull = __importStar(require("./Pull"))
const SER = __importStar(require("./sinkEndReason"))
const Take = __importStar(require("./Take"))
const Z = __importStar(require("./zip"))
/**
 * Submerges the error case of an `Either` into the `ZStream`.
 */
function absolve(xs) {
  return C.mapM_(xs, (_) => T.fromEither(() => _, fileName_1 + ":42:41"))
}
exports.absolve = absolve
/**
 * Aggregates elements of this stream using the provided sink for as long
 * as the downstream operators on the stream are busy.
 *
 * This operator divides the stream into two asynchronous "islands". Operators upstream
 * of this operator run on one fiber, while downstream operators run on another. Whenever
 * the downstream fiber is busy processing elements, the upstream fiber will feed elements
 * into the sink until it signals completion.
 *
 * Any sink can be used here, but see `Sink.foldWeightedM` and `Sink.foldUntilM` for
 * sinks that cover the common usecases.
 */
function aggregateAsync_(self, sink) {
  return aggregateAsyncWithin_(self, sink, SC.forever)
}
exports.aggregateAsync_ = aggregateAsync_
/**
 * Aggregates elements of this stream using the provided sink for as long
 * as the downstream operators on the stream are busy.
 *
 * This operator divides the stream into two asynchronous "islands". Operators upstream
 * of this operator run on one fiber, while downstream operators run on another. Whenever
 * the downstream fiber is busy processing elements, the upstream fiber will feed elements
 * into the sink until it signals completion.
 *
 * Any sink can be used here, but see `Sink.foldWeightedM` and `Sink.foldUntilM` for
 * sinks that cover the common usecases.
 *
 * @dataFirst aggregateAsync_
 */
function aggregateAsync(sink) {
  return (self) => aggregateAsync_(self, sink)
}
exports.aggregateAsync = aggregateAsync
/**
 * Like `aggregateAsyncWithinEither`, but only returns the `Right` results.
 */
function aggregateAsyncWithin_(self, sink, schedule) {
  return collect_(
    aggregateAsyncWithinEither_(self, sink, schedule),
    E.fold(
      () => O.none,
      (v) => O.some(v)
    )
  )
}
exports.aggregateAsyncWithin_ = aggregateAsyncWithin_
/**
 * Like `aggregateAsyncWithinEither`, but only returns the `Right` results.
 *
 * @dataFirst aggregateAsyncWithin_
 */
function aggregateAsyncWithin(sink, schedule) {
  return (self) => aggregateAsyncWithin_(self, sink, schedule)
}
exports.aggregateAsyncWithin = aggregateAsyncWithin
/**
 * Aggregates elements using the provided sink until it completes, or until the
 * delay signalled by the schedule has passed.
 *
 * This operator divides the stream into two asynchronous islands. Operators upstream
 * of this operator run on one fiber, while downstream operators run on another. Elements
 * will be aggregated by the sink until the downstream fiber pulls the aggregated value,
 * or until the schedule's delay has passed.
 *
 * Aggregated elements will be fed into the schedule to determine the delays between
 * pulls.
 */
function aggregateAsyncWithinEither_(self, sink, schedule) {
  const deps = tracing_1.traceCall(T.tuple, fileName_1 + ":157:23")(
    HO.make(),
    Ref.makeRef(new SER.SinkEnd()),
    Ref.makeRef(A.empty()),
    SC.driver(schedule)
  )
  return C.chain_(
    fromEffect(deps),
    ({ tuple: [handoff, sinkEndReason, sinkLeftovers, scheduleDriver] }) => {
      const handoffProducer = CH.readWithCause(
        (_in) =>
          CH.zipRight_(
            CH.fromEffect(HO.offer(handoff, new HO.Emit(_in))),
            handoffProducer
          ),
        (cause) => CH.fromEffect(HO.offer(handoff, new HO.Halt(cause))),
        (_) => CH.fromEffect(HO.offer(handoff, new HO.End(new SER.UpstreamEnd())))
      )
      const handoffConsumer = CH.unwrap(
        T.chain_(
          Ref.getAndSet_(sinkLeftovers, A.empty()),
          (leftovers) => {
            if (A.isEmpty(leftovers)) {
              return T.succeed(
                CH.zipRight_(CH.write(leftovers), handoffConsumer),
                fileName_1 + ":196:29"
              )
            } else {
              return T.map_(
                HO.take(handoff),
                (_) => {
                  switch (_._typeId) {
                    case HO.EmitTypeId:
                      return CH.zipRight_(CH.write(_.els), handoffConsumer)
                    case HO.HaltTypeId:
                      return CH.halt(_.error)
                    case HO.EndTypeId:
                      return CH.fromEffect(Ref.set_(sinkEndReason, _.reason))
                  }
                },
                fileName_1 + ":198:26"
              )
            }
          },
          fileName_1 + ":194:17"
        )
      )
      const scheduledAggregator = (lastB) => {
        const timeout = T.foldCauseM_(
          scheduleDriver.next(lastB),
          (_) =>
            E.fold_(
              CS.failureOrCause(_),
              (_) => HO.offer(handoff, new HO.End(new SER.ScheduleTimeout())),
              (cause) => HO.offer(handoff, new HO.Halt(cause))
            ),
          (c) => HO.offer(handoff, new HO.End(new SER.ScheduleEnd(c))),
          fileName_1 + ":223:38"
        )
        return CH.chain_(
          CH.managed_(T.forkManaged(timeout, fileName_1 + ":235:36"), (fiber) => {
            return CH.chain_(
              CH.doneCollect(handoffConsumer[">>>"](sink.channel)),
              ({ tuple: [leftovers, b] }) => {
                return CH.zipRight_(
                  CH.fromEffect(
                    T.zipRight_(
                      F.interrupt(fiber),
                      Ref.set_(sinkLeftovers, A.flatten(leftovers)),
                      fileName_1 + ":241:32"
                    )
                  ),
                  CH.unwrap(
                    Ref.modify_(sinkEndReason, (reason) => {
                      switch (reason._typeId) {
                        case SER.ScheduleEndTypeId:
                          return Tp.tuple(
                            CH.as_(
                              CH.write(A.from([E.right(b), E.left(reason.c)])),
                              O.some(b)
                            ),
                            new SER.SinkEnd()
                          )
                        case SER.ScheduleTimeoutTypeId:
                          return Tp.tuple(
                            CH.as_(CH.write(A.single(E.right(b))), O.some(b)),
                            new SER.SinkEnd()
                          )
                        case SER.SinkEndTypeId:
                          return Tp.tuple(
                            CH.as_(CH.write(A.single(E.right(b))), O.some(b)),
                            new SER.SinkEnd()
                          )
                        case SER.UpstreamEndTypeId:
                          return Tp.tuple(
                            CH.as_(CH.write(A.single(E.right(b))), O.none),
                            new SER.UpstreamEnd()
                          )
                      }
                    })
                  )
                )
              }
            )
          }),
          (_) => {
            if (O.isNone(_)) {
              return CH.unit
            } else {
              return scheduledAggregator(_)
            }
          }
        )
      }
      return Z.zipRight_(
        C.managed(
          M.fork(
            CH.runManaged(self.channel[">>>"](handoffProducer)),
            fileName_1 + ":290:83"
          )
        ),
        new core_1.Stream(scheduledAggregator(O.none))
      )
    }
  )
}
exports.aggregateAsyncWithinEither_ = aggregateAsyncWithinEither_
/**
 * Aggregates elements using the provided sink until it completes, or until the
 * delay signalled by the schedule has passed.
 *
 * This operator divides the stream into two asynchronous islands. Operators upstream
 * of this operator run on one fiber, while downstream operators run on another. Elements
 * will be aggregated by the sink until the downstream fiber pulls the aggregated value,
 * or until the schedule's delay has passed.
 *
 * Aggregated elements will be fed into the schedule to determine the delays between
 * pulls.
 *
 * @dataFirst aggregateAsyncWithinEither_
 */
function aggregateAsyncWithinEither(sink, schedule) {
  return (self) => aggregateAsyncWithinEither_(self, sink, schedule)
}
exports.aggregateAsyncWithinEither = aggregateAsyncWithinEither
/**
 * Maps the success values of this stream to the specified constant value.
 */
function as_(self, a2) {
  return C.map_(self, (_) => a2)
}
exports.as_ = as_
/**
 * Maps the success values of this stream to the specified constant value.
 *
 * @dataFirst as_
 */
function as(a2) {
  return (self) => as_(self, a2)
}
exports.as = as
/**
 * Returns a stream whose failure and success channels have been mapped by
 * the specified pair of functions, `f` and `g`.
 */
function bimap_(self, f, g) {
  return C.map_(mapError_(self, f), g)
}
exports.bimap_ = bimap_
/**
 * Returns a stream whose failure and success channels have been mapped by
 * the specified pair of functions, `f` and `g`.
 *
 * @dataFirst bimap_
 */
function bimap(f, g) {
  return (self) => bimap_(self, f, g)
}
exports.bimap = bimap
/**
 * Fan out the stream, producing a dynamic number of streams that have the same elements as this stream.
 * The driver stream will only ever advance of the `maximumLag` chunks before the
 * slowest downstream stream.
 */
function broadcastDynamic_(self, maximumLag) {
  return M.map_(
    broadcastedQueuesDynamic_(self, maximumLag),
    (_) => flattenTake(C.chain_(C.managed(_), fromQueue())),
    fileName_1 + ":366:16"
  )
}
exports.broadcastDynamic_ = broadcastDynamic_
/**
 * Fan out the stream, producing a dynamic number of streams that have the same elements as this stream.
 * The driver stream will only ever advance of the `maximumLag` chunks before the
 * slowest downstream stream.
 *
 * @dataFirst broadcastDynamic_
 */
function broadcastDynamic(maximumLag) {
  return (self) => broadcastDynamic_(self, maximumLag)
}
exports.broadcastDynamic = broadcastDynamic
/**
 * Converts the stream to a managed list of queues. Every value will be replicated to every queue with the
 * slowest queue being allowed to buffer `maximumLag` chunks before the driver is backpressured.
 *
 * Queues can unsubscribe from upstream by shutting down.
 */
function broadcastedQueues_(self, n, maximumLag) {
  return M.map_(
    M.tap_(
      M.bind_(
        M.bind_(
          M.do,
          "hub",
          () => T.toManaged(H.makeBounded(maximumLag)),
          fileName_1 + ":395:11"
        ),
        "queues",
        ({ hub }) =>
          M.collectAll(
            A.fill(n, () => H.subscribe(hub)),
            fileName_1 + ":396:47"
          ),
        fileName_1 + ":396:11"
      ),
      ({ hub }) => M.fork(runIntoHubManaged_(self, hub), fileName_1 + ":397:30"),
      fileName_1 + ":397:10"
    ),
    ({ queues }) => queues,
    fileName_1 + ":398:10"
  )
}
exports.broadcastedQueues_ = broadcastedQueues_
/**
 * Converts the stream to a managed list of queues. Every value will be replicated to every queue with the
 * slowest queue being allowed to buffer `maximumLag` chunks before the driver is backpressured.
 *
 * Queues can unsubscribe from upstream by shutting down.
 *
 * @dataFirst broadcastedQueues_
 */
function broadcastedQueues(n, maximumLag) {
  return (self) => broadcastedQueues_(self, n, maximumLag)
}
exports.broadcastedQueues = broadcastedQueues
/**
 * Converts the stream to a managed dynamic amount of queues. Every chunk will be replicated to every queue with the
 * slowest queue being allowed to buffer `maximumLag` chunks before the driver is backpressured.
 *
 * Queues can unsubscribe from upstream by shutting down.
 */
function broadcastedQueuesDynamic_(self, maximumLag) {
  return M.map_(toHub_(self, maximumLag), (_) => H.subscribe(_), fileName_1 + ":428:16")
}
exports.broadcastedQueuesDynamic_ = broadcastedQueuesDynamic_
/**
 * Converts the stream to a managed dynamic amount of queues. Every chunk will be replicated to every queue with the
 * slowest queue being allowed to buffer `maximumLag` chunks before the driver is backpressured.
 *
 * Queues can unsubscribe from upstream by shutting down.
 *
 * @dataFirst broadcastedQueuesDynamic_
 */
function broadcastedQueuesDynamic(maximumLag) {
  return (self) => broadcastedQueuesDynamic_(self, maximumLag)
}
exports.broadcastedQueuesDynamic = broadcastedQueuesDynamic
/**
 * Allows a faster producer to progress independently of a slower consumer by buffering
 * up to `capacity` chunks in a queue.
 */
function buffer_(self, capacity) {
  const queue = toQueue_(self, capacity)
  return new core_1.Stream(
    CH.managed_(queue, (queue) => {
      const process = CH.chain_(
        CH.fromEffect(Q.take(queue)),
        Take.fold(
          CH.end(undefined),
          (error) => CH.halt(error),
          (value) => CH.zipRight_(CH.write(value), process)
        )
      )
      return process
    })
  )
}
exports.buffer_ = buffer_
/**
 * Allows a faster producer to progress independently of a slower consumer by buffering
 * up to `capacity` chunks in a queue.
 *
 * @dataFirst buffer_
 */
function buffer(capacity) {
  return (self) => buffer_(self, capacity)
}
exports.buffer = buffer
/**
 * Allows a faster producer to progress independently of a slower consumer by buffering
 * elements into an unbounded queue.
 */
function bufferUnbounded(self) {
  const queue = toQueueUnbounded(self)
  return new core_1.Stream(
    CH.managed_(queue, (queue) => {
      const process = CH.chain_(
        CH.fromEffect(Q.take(queue)),
        Take.fold(
          CH.end(undefined),
          (error) => CH.halt(error),
          (value) => CH.zipRight_(CH.write(value), process)
        )
      )
      return process
    })
  )
}
exports.bufferUnbounded = bufferUnbounded
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with a typed error.
 */
function catchAll_(self, f) {
  return catchAllCause_(self, (_) => E.fold_(CS.failureOrCause(_), f, (_) => halt(_)))
}
exports.catchAll_ = catchAll_
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with a typed error.
 *
 * @dataFirst catchAll_
 */
function catchAll(f) {
  return (self) => catchAll_(self, f)
}
exports.catchAll = catchAll
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails. Allows recovery from all causes of failure, including interruption if the
 * stream is uninterruptible.
 */
function catchAllCause_(self, f) {
  const channel = CH.catchAllCause_(self.channel, (_) => f(_).channel)
  return new core_1.Stream(channel)
}
exports.catchAllCause_ = catchAllCause_
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails. Allows recovery from all causes of failure, including interruption if the
 * stream is uninterruptible.
 *
 * @dataFirst catchAllCause_
 */
function catchAllCause(f) {
  return (self) => catchAllCause_(self, f)
}
exports.catchAllCause = catchAllCause
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with some typed error.
 */
function catchSome_(self, pf) {
  return catchAll_(self, (e) =>
    O.fold_(
      pf(e),
      () => fail(e),
      (_) => _
    )
  )
}
exports.catchSome_ = catchSome_
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with some typed error.
 *
 * @dataFirst catchSome_
 */
function catchSome(pf) {
  return (self) => catchSome_(self, pf)
}
exports.catchSome = catchSome
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with some errors. Allows recovery from all causes of failure, including interruption if the
 * stream is uninterruptible.
 */
function catchSomeCause_(self, pf) {
  return catchAllCause_(self, (e) =>
    O.fold_(
      pf(e),
      () => halt(e),
      (_) => _
    )
  )
}
exports.catchSomeCause_ = catchSomeCause_
/**
 * Switches over to the stream produced by the provided function in case this one
 * fails with some errors. Allows recovery from all causes of failure, including interruption if the
 * stream is uninterruptible.
 *
 * @dataFirst catchSomeCause_
 */
function catchSomeCause(pf) {
  return (self) => catchSomeCause_(self, pf)
}
exports.catchSomeCause = catchSomeCause
class Rechunker {
  constructor(n) {
    this.n = n
    this.builder = A.builder()
    this.pos = 0
  }
  write(elem) {
    this.builder.append(elem)
    this.pos += 1
    if (this.pos === this.n) {
      const result = this.builder.build()
      this.builder = A.builder()
      this.pos = 0
      return result
    }
    return null
  }
  emitOfNotEmpty() {
    if (this.pos !== 0) {
      return CH.write(this.builder.build())
    } else {
      return CH.unit
    }
  }
}
/**
 * Re-chunks the elements of the stream into chunks of
 * `n` elements each.
 * The last chunk might contain less than `n` elements
 */
function chunkN_(self, n) {
  return C.unwrap(
    T.succeedWith(() => {
      const rechunker = new Rechunker(n)
      const process = CH.readWithCause(
        (chunk) => {
          const chunkSize = A.size(chunk)
          if (chunkSize > 0) {
            let chunks = L.empty()
            let result = null
            let i = 0
            while (i < chunkSize) {
              while (i < chunkSize && result === null) {
                result = rechunker.write(A.unsafeGet_(chunk, i))
                i += 1
              }
              if (result !== null) {
                chunks = L.prepend_(chunks, result)
                result = null
              }
            }
            return CH.zipRight_(CH.writeAll(...L.toArray(L.reverse(chunks))), process)
          }
          return process
        },
        (cause) => CH.zipRight_(rechunker.emitOfNotEmpty(), CH.halt(cause)),
        (_) => rechunker.emitOfNotEmpty()
      )
      return new core_1.Stream(self.channel[">>>"](process))
    }, fileName_1 + ":672:18")
  )
}
exports.chunkN_ = chunkN_
/**
 * Re-chunks the elements of the stream into chunks of
 * `n` elements each.
 * The last chunk might contain less than `n` elements
 *
 * @dataFirst chunkN_
 */
function chunkN(n) {
  return (self) => chunkN_(self, n)
}
exports.chunkN = chunkN
/**
 * Exposes the underlying chunks of the stream as a stream of chunks of elements
 */
function chunks(self) {
  return mapChunks_(self, A.single)
}
exports.chunks = chunks
/**
 * Performs a filter and map in a single step.
 */
function collect_(self, f) {
  return mapChunks_(self, A.filterMap(f))
}
exports.collect_ = collect_
/**
 * Performs a filter and map in a single step.
 *
 * @dataFirst collect_
 */
function collect(f) {
  return (self) => collect_(self, f)
}
exports.collect = collect
/**
 * Filters any `Right` values.
 */
function collectLeft(self) {
  return collect_(
    self,
    E.fold(
      (a) => O.some(a),
      (_) => O.none
    )
  )
}
exports.collectLeft = collectLeft
/**
 * Filters any `Left` values.
 */
function collectRight(self) {
  return collect_(
    self,
    E.fold(
      (_) => O.none,
      (a) => O.some(a)
    )
  )
}
exports.collectRight = collectRight
/**
 * Filters any `None` values.
 */
function collectSome(self) {
  return collect_(self, (a) => a)
}
exports.collectSome = collectSome
/**
 * Filters any `Exit.Failure` values.
 */
function collectSuccess(self) {
  return collect_(
    self,
    Ex.fold(
      (_) => O.none,
      (a) => O.some(a)
    )
  )
}
exports.collectSuccess = collectSuccess
/**
 * Performs an effectful filter and map in a single step.
 */
function collectM_(self, pf) {
  return C.loopOnPartialChunksElements_(self, (a, emit) =>
    O.fold_(
      pf(a),
      () => T.unit,
      (_) => T.asUnit(T.chain_(_, emit, fileName_1 + ":815:31"), fileName_1 + ":815:22")
    )
  )
}
exports.collectM_ = collectM_
/**
 * Performs an effectful filter and map in a single step.
 *
 * @dataFirst collectM_
 */
function collectM(pf) {
  return (self) => collectM_(self, pf)
}
exports.collectM = collectM
/**
 * Transforms all elements of the stream for as long as the specified partial function is defined.
 */
function collectWhile_(self, pf) {
  const loop = CH.readWith(
    (_in) => {
      const mapped = A.collectWhile_(_in, pf)
      if (A.size(mapped) === A.size(_in)) {
        return CH.zipRight_(CH.write(mapped), loop)
      } else {
        return CH.write(mapped)
      }
    },
    CH.fail,
    CH.succeed
  )
  return new core_1.Stream(self.channel[">>>"](loop))
}
exports.collectWhile_ = collectWhile_
/**
 * Transforms all elements of the stream for as long as the specified partial function is defined.
 *
 * @dataFirst collectWhile_
 */
function collectWhile(pf) {
  return (self) => collectWhile_(self, pf)
}
exports.collectWhile = collectWhile
/**
 * Terminates the stream when encountering the first `Right`.
 */
function collectWhileLeft(self) {
  return collectWhile_(
    self,
    E.fold(
      (l) => O.some(l),
      (_) => O.none
    )
  )
}
exports.collectWhileLeft = collectWhileLeft
/**
 * Effectfully transforms all elements of the stream for as long as the specified partial function is defined.
 */
function collectWhileM_(self, pf) {
  return C.loopOnPartialChunks_(self, (chunk, emit) => {
    const pfSome = (a) =>
      O.fold_(
        pf(a),
        () => T.succeed(false, fileName_1 + ":888:24"),
        (_) =>
          T.as_(T.chain_(_, emit, fileName_1 + ":889:30"), true, fileName_1 + ":889:21")
      )
    const loop = (chunk) => {
      if (A.isEmpty(chunk)) {
        return T.succeed(true, fileName_1 + ":894:25")
      } else {
        return T.chain_(
          pfSome(A.unsafeHead(chunk)),
          (cont) => {
            if (cont) {
              return loop(A.unsafeTail(chunk))
            } else {
              return T.succeed(false, fileName_1 + ":900:29")
            }
          },
          fileName_1 + ":896:24"
        )
      }
    }
    return loop(chunk)
  })
}
exports.collectWhileM_ = collectWhileM_
/**
 * Effectfully transforms all elements of the stream for as long as the specified partial function is defined.
 *
 * @dataFirst collectWhileM_
 */
function collectWhileM(pf) {
  return (self) => collectWhileM_(self, pf)
}
exports.collectWhileM = collectWhileM
/**
 * Terminates the stream when encountering the first `None`.
 */
function collectWhileSome(self) {
  return collectWhile_(self, Function_1.identity)
}
exports.collectWhileSome = collectWhileSome
/**
 * Terminates the stream when encountering the first `Left`.
 */
function collectWhileRight(self) {
  return collectWhile_(
    self,
    E.fold(
      () => O.none,
      (r) => O.some(r)
    )
  )
}
exports.collectWhileRight = collectWhileRight
/**
 * Terminates the stream when encountering the first `Exit.Failure`.
 */
function collectWhileSuccess(self) {
  return collectWhile_(
    self,
    Ex.fold(
      () => O.none,
      (r) => O.some(r)
    )
  )
}
exports.collectWhileSuccess = collectWhileSuccess
/**
 * Combines the elements from this stream and the specified stream by repeatedly applying the
 * function `f` to extract an element using both sides and conceptually "offer"
 * it to the destination stream. `f` can maintain some internal state to control
 * the combining process, with the initial state being specified by `s`.
 *
 * Where possible, prefer `Stream#combineChunks` for a more efficient implementation.
 */
function combine(self, that) {
  return (s) => (f) => {
    return C.unwrapManaged(
      M.map_(
        M.bind_(
          M.bind_(
            M.do,
            "left",
            () => M.mapM_(C.toPull(self), BP.make, fileName_1 + ":983:39"),
            fileName_1 + ":983:17"
          ),
          "right",
          () => M.mapM_(C.toPull(that), BP.make, fileName_1 + ":984:40"),
          fileName_1 + ":984:17"
        ),
        ({ left, right }) =>
          unfoldM(s)((s) =>
            T.chain_(
              f(s, BP.pullElement(left), BP.pullElement(right)),
              (_) =>
                T.optional(T.done(_, fileName_1 + ":988:34"), fileName_1 + ":988:27"),
              fileName_1 + ":987:23"
            )
          ),
        fileName_1 + ":985:16"
      )
    )
  }
}
exports.combine = combine
/**
 * Concatenates the specified stream with this stream, resulting in a stream
 * that emits the elements from this stream and then the elements from the specified stream.
 */
function concat_(self, that) {
  return new core_1.Stream(CH.zipRight_(self.channel, that.channel))
}
exports.concat_ = concat_
/**
 * Concatenates the specified stream with this stream, resulting in a stream
 * that emits the elements from this stream and then the elements from the specified stream.
 *
 * @dataFirst concat_
 */
function concat(that) {
  return (self) => concat_(self, that)
}
exports.concat = concat
/**
 * Composes this stream with the specified stream to create a cartesian product of elements.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 */
function cross_(self, that) {
  return new core_1.Stream(
    CH.concatMap_(self.channel, (a) =>
      CH.mapOut_(that.channel, (b) =>
        A.chain_(a, (a) => A.map_(b, (b) => Tp.tuple(a, b)))
      )
    )
  )
}
exports.cross_ = cross_
/**
 * Composes this stream with the specified stream to create a cartesian product of elements.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 *
 * @dataFirst cross_
 */
function cross(that) {
  return (self) => cross_(self, that)
}
exports.cross = cross
/**
 * Composes this stream with the specified stream to create a cartesian product of elements,
 * but keeps only elements from this stream.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 */
function crossLeft_(self, that) {
  return C.map_(cross_(self, that), Tp.get(0))
}
exports.crossLeft_ = crossLeft_
/**
 * Composes this stream with the specified stream to create a cartesian product of elements,
 * but keeps only elements from this stream.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 *
 * @dataFirst crossLeft_
 */
function crossLeft(that) {
  return (self) => crossLeft_(self, that)
}
exports.crossLeft = crossLeft
/**
 * Composes this stream with the specified stream to create a cartesian product of elements,
 * but keeps only elements from the other stream.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 */
function crossRight_(self, that) {
  return C.map_(cross_(self, that), Tp.get(1))
}
exports.crossRight_ = crossRight_
/**
 * Composes this stream with the specified stream to create a cartesian product of elements,
 * but keeps only elements from the other stream.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 *
 * @dataFirst crossRight_
 */
function crossRight(that) {
  return (self) => crossRight_(self, that)
}
exports.crossRight = crossRight
/**
 * Composes this stream with the specified stream to create a cartesian product of elements
 * with a specified function.
 * The `that` stream would be run multiple times, for every element in the `this` stream.
 */
function crossWith(self, that) {
  return (f) => C.chain_(self, (l) => C.map_(that, (r) => f(l, r)))
}
exports.crossWith = crossWith
/**
 * More powerful version of `Stream#broadcast`. Allows to provide a function that determines what
 * queues should receive which elements. The decide function will receive the indices of the queues
 * in the resulting list.
 */
function distributedWith_(self, n, maximumLag, decide) {
  return M.chain_(
    T.toManaged(P.make()),
    (prom) => {
      return M.chain_(
        distributedWithDynamic_(
          self,
          maximumLag,
          (a) => T.chain_(P.await(prom), (_) => _(a), fileName_1 + ":1122:29"),
          (_) => T.unit
        ),
        (next) =>
          T.toManaged(
            T.chain_(
              T.collectAll(
                A.map_(A.range(0, n), (id) =>
                  T.map_(
                    next,
                    ({ tuple: [key, queue] }) => Tp.tuple(Tp.tuple(key, id), queue),
                    fileName_1 + ":1129:23"
                  )
                ),
                fileName_1 + ":1127:25"
              ),
              (entries) => {
                const {
                  tuple: [mappings, queues]
                } = A.reduceRight_(
                  entries,
                  Tp.tuple(HashMap.make(), L.empty()),
                  ({ tuple: [mapping, queue] }, { tuple: [mappings, queues] }) =>
                    Tp.tuple(
                      HashMap.set_(mappings, Tp.get_(mapping, 0), Tp.get_(mapping, 1)),
                      L.prepend_(queues, queue)
                    )
                )
                return T.as_(
                  P.succeed_(prom, (a) =>
                    T.map_(
                      decide(a),
                      (f) => (key) => f(HashMap.unsafeGet_(mappings, key)),
                      fileName_1 + ":1152:25"
                    )
                  ),
                  queues,
                  fileName_1 + ":1150:27"
                )
              },
              fileName_1 + ":1134:20"
            )
          ),
        fileName_1 + ":1118:22"
      )
    },
    fileName_1 + ":1115:18"
  )
}
exports.distributedWith_ = distributedWith_
/**
 * More powerful version of `Stream#broadcast`. Allows to provide a function that determines what
 * queues should receive which elements. The decide function will receive the indices of the queues
 * in the resulting list.
 *
 * @dataFirst distributedWith_
 */
function distributedWith(n, maximumLag, decide) {
  return (self) => distributedWith_(self, n, maximumLag, decide)
}
exports.distributedWith = distributedWith
const distributedWithDynamicId = new AtomicNumber_1.AtomicNumber(0)
/**
 * More powerful version of `Stream#distributedWith`. This returns a function that will produce
 * new queues and corresponding indices.
 * You can also provide a function that will be executed after the final events are enqueued in all queues.
 * Shutdown of the queues is handled by the driver.
 * Downstream users can also shutdown queues manually. In this case the driver will
 * continue but no longer backpressure on them.
 */
function distributedWithDynamic_(self, maximumLag, decide, done) {
  return M.map_(
    M.bind_(
      M.bind_(
        M.do,
        "queuesRef",
        () =>
          T.toManagedRelease_(Ref.makeRef(HashMap.make()), (_) =>
            T.chain_(
              Ref.get(_),
              (qs) =>
                T.forEach_(
                  HashMap.values(qs),
                  (_) => Q.shutdown(_),
                  fileName_1 + ":1207:23"
                ),
              fileName_1 + ":1206:19"
            )
          ),
        fileName_1 + ":1200:11"
      ),
      "add",
      ({ queuesRef }) => {
        const offer = (a) =>
          T.asUnit(
            T.tap_(
              T.bind_(
                T.bind_(
                  T.do,
                  "shouldProcess",
                  () => decide(a),
                  fileName_1 + ":1215:17"
                ),
                "queues",
                () => Ref.get(queuesRef),
                fileName_1 + ":1216:17"
              ),
              ({ queues, shouldProcess }) =>
                T.chain_(
                  T.reduce_(
                    queues,
                    L.empty(),
                    (acc, [id, queue]) => {
                      if (shouldProcess(id)) {
                        return T.foldCauseM_(
                          Q.offer_(queue, Ex.succeed(a)),
                          (c) =>
                            CS.interrupted(c)
                              ? T.succeed(L.prepend_(acc, id), fileName_1 + ":1224:52")
                              : T.halt(c, fileName_1 + ":1224:82"),
                          (_) => T.succeed(acc, fileName_1 + ":1225:37"),
                          fileName_1 + ":1221:39"
                        )
                      } else {
                        return T.succeed(acc, fileName_1 + ":1228:35")
                      }
                    },
                    fileName_1 + ":1219:24"
                  ),
                  (ids) =>
                    L.isEmpty(ids)
                      ? T.unit
                      : Ref.update_(queuesRef, HashMap.removeMany(ids)),
                  fileName_1 + ":1231:22"
                ),
              fileName_1 + ":1217:16"
            ),
            fileName_1 + ":1238:19"
          )
        return M.map_(
          M.tap_(
            M.let_(
              M.bind_(
                M.bind_(
                  M.do,
                  "queuesLock",
                  () => T.toManaged(SM.makeSemaphore(1)),
                  fileName_1 + ":1243:15"
                ),
                "newQueue",
                () =>
                  T.toManaged(
                    Ref.makeRef(
                      T.map_(
                        T.tap_(
                          T.bind_(
                            T.bind_(
                              T.do,
                              "queue",
                              () => Q.makeBounded(maximumLag, fileName_1 + ":1250:32"),
                              fileName_1 + ":1249:23"
                            ),
                            "id",
                            () =>
                              T.succeedWith(
                                () => distributedWithDynamicId.incrementAndGet(),
                                fileName_1 + ":1253:32"
                              ),
                            fileName_1 + ":1252:23"
                          ),
                          ({ id, queue }) =>
                            Ref.update_(queuesRef, HashMap.set(id, queue)),
                          fileName_1 + ":1255:22"
                        ),
                        ({ id, queue }) => Tp.tuple(id, queue),
                        fileName_1 + ":1258:22"
                      )
                    )
                  ),
                fileName_1 + ":1244:15"
              ),
              "finalize",
              ({ newQueue, queuesLock }) =>
                (endTake) =>
                  SM.withPermit_(
                    T.asUnit(
                      T.tap_(
                        T.tap_(
                          T.bind_(
                            T.tap_(
                              T.do,
                              () =>
                                Ref.set_(
                                  newQueue,
                                  T.map_(
                                    T.tap_(
                                      T.bind_(
                                        T.tap_(
                                          T.bind_(
                                            T.do,
                                            "queue",
                                            () =>
                                              Q.makeBounded(1, fileName_1 + ":1276:40"),
                                            fileName_1 + ":1275:31"
                                          ),
                                          ({ queue }) => Q.offer_(queue, endTake),
                                          fileName_1 + ":1278:30"
                                        ),
                                        "id",
                                        () =>
                                          T.succeedWith(
                                            () =>
                                              distributedWithDynamicId.incrementAndGet(),
                                            fileName_1 + ":1280:40"
                                          ),
                                        fileName_1 + ":1279:31"
                                      ),
                                      ({ id, queue }) =>
                                        Ref.update_(queuesRef, HashMap.set(id, queue)),
                                      fileName_1 + ":1284:30"
                                    ),
                                    ({ id, queue }) => Tp.tuple(id, queue),
                                    fileName_1 + ":1287:30"
                                  )
                                ),
                              fileName_1 + ":1270:24"
                            ),
                            "queues",
                            () =>
                              T.map_(
                                Ref.get(queuesRef),
                                HashMap.values,
                                fileName_1 + ":1291:48"
                              ),
                            fileName_1 + ":1291:25"
                          ),
                          ({ queues }) =>
                            T.forEach_(
                              queues,
                              (queue) =>
                                T.catchSomeCause_(
                                  Q.offer_(queue, endTake),
                                  (c) => {
                                    if (CS.interrupted(c)) {
                                      return O.some(T.unit)
                                    } else {
                                      return O.none
                                    }
                                  },
                                  fileName_1 + ":1294:40"
                                ),
                              fileName_1 + ":1293:31"
                            ),
                          fileName_1 + ":1292:24"
                        ),
                        (_) => done(endTake),
                        fileName_1 + ":1303:24"
                      ),
                      fileName_1 + ":1304:27"
                    ),
                    queuesLock
                  ),
              fileName_1 + ":1263:14"
            ),
            ({ finalize }) =>
              M.fork(
                M.foldCauseM_(
                  runForEachManaged_(self, offer),
                  (cause) => T.toManaged(finalize(Ex.halt(CS.map_(cause, O.some)))),
                  (_) => T.toManaged(finalize(Ex.fail(O.none))),
                  fileName_1 + ":1312:25"
                ),
                fileName_1 + ":1316:19"
              ),
            fileName_1 + ":1309:14"
          ),
          ({ newQueue, queuesLock }) =>
            SM.withPermit_(
              T.flatten(Ref.get(newQueue), fileName_1 + ":1320:35"),
              queuesLock
            ),
          fileName_1 + ":1319:14"
        )
      },
      fileName_1 + ":1211:11"
    ),
    ({ add }) => add,
    fileName_1 + ":1324:10"
  )
}
exports.distributedWithDynamic_ = distributedWithDynamic_
/**
 * More powerful version of `Stream#distributedWith`. This returns a function that will produce
 * new queues and corresponding indices.
 * You can also provide a function that will be executed after the final events are enqueued in all queues.
 * Shutdown of the queues is handled by the driver.
 * Downstream users can also shutdown queues manually. In this case the driver will
 * continue but no longer backpressure on them.
 *
 * @dataFirst distributedWithDynamic_
 */
function distributedWithDynamic(maximumLag, decide, done) {
  return (self) => distributedWithDynamic_(self, maximumLag, decide, done)
}
exports.distributedWithDynamic = distributedWithDynamic
/**
 * Converts this stream to a stream that executes its effects but emits no
 * elements. Useful for sequencing effects using streams:
 */
function drain(self) {
  return new core_1.Stream(CH.drain(self.channel))
}
exports.drain = drain
/**
 * Drains the provided stream in the background for as long as this stream is running.
 * If this stream ends before `other`, `other` will be interrupted. If `other` fails,
 * this stream will fail with that error.
 */
function drainFork_(self, other) {
  return C.chain_(fromEffect(P.make()), (bgDied) =>
    Z.zipRight_(
      C.managed(
        M.fork(
          M.catchAllCause_(
            runForEachManaged_(other, (_) => T.unit),
            (_) => T.toManaged(P.halt_(bgDied, _)),
            fileName_1 + ":1369:26"
          ),
          fileName_1 + ":1370:17"
        )
      ),
      interruptWhenP_(self, bgDied)
    )
  )
}
exports.drainFork_ = drainFork_
/**
 * Drains the provided stream in the background for as long as this stream is running.
 * If this stream ends before `other`, `other` will be interrupted. If `other` fails,
 * this stream will fail with that error.
 *
 * @dataFirst drainFork_
 */
function drainFork(other) {
  return (self) => drainFork_(self, other)
}
exports.drainFork = drainFork
/**
 * Drops the specified number of elements from this stream.
 */
function drop_(self, n) {
  const loop = (r) =>
    CH.readWith(
      (_in) => {
        const dropped = A.drop_(_in, r)
        const leftover = Math.max(r - A.size(_in), 0)
        const more = A.isEmpty(_in) || leftover > 0
        if (more) {
          return loop(leftover)
        } else {
          return CH.zipRight_(CH.write(dropped), CH.identity())
        }
      },
      (e) => CH.fail(e),
      (_) => CH.unit
    )
  return new core_1.Stream(self.channel[">>>"](loop(n)))
}
exports.drop_ = drop_
/**
 * Drops the specified number of elements from this stream.
 *
 * @dataFirst drop_
 */
function drop(n) {
  return (self) => drop_(self, n)
}
exports.drop = drop
/**
 * Drops all elements of the stream for as long as the specified predicate
 * evaluates to `true`.
 */
function dropWhile_(self, f) {
  const loop = CH.readWith(
    (_in) => {
      const leftover = A.dropWhile_(_in, f)
      const more = A.isEmpty(_in)
      if (more) {
        return loop
      } else {
        return CH.zipRight_(CH.write(leftover), CH.identity())
      }
    },
    (e) => CH.fail(e),
    (_) => CH.unit
  )
  return new core_1.Stream(self.channel[">>>"](loop))
}
exports.dropWhile_ = dropWhile_
/**
 * Drops all elements of the stream for as long as the specified predicate
 * evaluates to `true`.
 *
 * @dataFirst dropWhile_
 */
function dropWhile(f) {
  return (self) => dropWhile_(self, f)
}
exports.dropWhile = dropWhile
/**
 * Drops all elements of the stream until the specified predicate evaluates
 * to `true`.
 */
function dropUntil_(self, f) {
  return drop_(
    dropWhile_(self, (_) => !f(_)),
    1
  )
}
exports.dropUntil_ = dropUntil_
/**
 * Drops all elements of the stream until the specified predicate evaluates
 * to `true`.
 *
 * @dataFirst dropUntil_
 */
function dropUntil(f) {
  return (self) => dropUntil_(self, f)
}
exports.dropUntil = dropUntil
/**
 * Returns a stream whose failures and successes have been lifted into an
 * `Either`. The resulting stream cannot fail, because the failures have
 * been exposed as part of the `Either` success case.
 *
 * @note the stream will end as soon as the first error occurs.
 */
function either(self) {
  return catchAll_(C.map_(self, E.right), (e) => C.succeed(E.left(e)))
}
exports.either = either
/**
 * Executes the provided finalizer after this stream's finalizers run.
 */
function ensuring_(self, fin) {
  return new core_1.Stream(CH.ensuring_(self.channel, fin))
}
exports.ensuring_ = ensuring_
/**
 * Executes the provided finalizer after this stream's finalizers run.
 *
 * @dataFirst ensuring_
 */
function ensuring(fin) {
  return (self) => ensuring_(self, fin)
}
exports.ensuring = ensuring
function filter_(self, f) {
  return mapChunks_(self, A.filter(f))
}
exports.filter_ = filter_
function filter(f) {
  return (self) => filter_(self, f)
}
exports.filter = filter
/**
 * Executes a pure fold over the stream of values - reduces all elements in the stream to a value of type `S`.
 */
function runReduce(self, s) {
  return (f) =>
    M.use_(
      runReduceWhileManaged_(
        self,
        s,
        (_) => true,
        (s, a) => f(s, a)
      ),
      tracing_1.traceCallLast(T.succeed, fileName_1 + ":1561:16"),
      fileName_1 + ":1554:11"
    )
}
exports.runReduce = runReduce
/**
 * Executes an effectful fold over the stream of values.
 */
function runReduceM(self, s) {
  return (f) =>
    M.use_(
      runReduceWhileManagedM(self, s)((_) => true)(f),
      tracing_1.traceCallLast(T.succeed, fileName_1 + ":1570:70"),
      fileName_1 + ":1570:11"
    )
}
exports.runReduceM = runReduceM
/**
 * Executes a pure fold over the stream of values.
 * Returns a Managed value that represents the scope of the stream.
 */
function runReduceManaged(self, s) {
  return (f) =>
    runReduceWhileManaged_(
      self,
      s,
      (_) => true,
      (s, a) => f(s, a)
    )
}
exports.runReduceManaged = runReduceManaged
/**
 * Executes an effectful fold over the stream of values.
 * Returns a Managed value that represents the scope of the stream.
 */
function runReduceManagedM(self, s) {
  return (f) => runReduceWhileManagedM(self, s)((_) => true)(f)
}
exports.runReduceManagedM = runReduceManagedM
/**
 * Reduces the elements in the stream to a value of type `S`.
 * Stops the fold early when the condition is not fulfilled.
 */
function runReduceWhile(self, s) {
  return (cont) => (f) =>
    M.use_(
      runReduceWhileManaged_(self, s, cont, (s, a) => f(s, a)),
      tracing_1.traceCallLast(T.succeed, fileName_1 + ":1606:18"),
      fileName_1 + ":1604:13"
    )
}
exports.runReduceWhile = runReduceWhile
/**
 * Executes an effectful fold over the stream of values.
 * Stops the fold early when the condition is not fulfilled.
 */
function runReduceWhileM(self, s) {
  return (cont) => (f) =>
    M.use_(
      runReduceWhileManagedM(self, s)(cont)(f),
      tracing_1.traceCallLast(T.succeed, fileName_1 + ":1617:65"),
      fileName_1 + ":1617:13"
    )
}
exports.runReduceWhileM = runReduceWhileM
/**
 * Executes a pure fold over the stream of values.
 * Returns a Managed value that represents the scope of the stream.
 * Stops the fold early when the condition is not fulfilled.
 */
function runReduceWhileManaged_(self, s, cont, f) {
  return runManaged_(self, SK.reduce(s)(cont)(f))
}
exports.runReduceWhileManaged_ = runReduceWhileManaged_
/**
 * Executes a pure fold over the stream of values.
 * Returns a Managed value that represents the scope of the stream.
 * Stops the fold early when the condition is not fulfilled.
 *
 * @dataFirst runFoldWhileManaged_
 */
function runReduceWhileManaged(s, cont, f) {
  return (self) => runReduceWhileManaged_(self, s, cont, f)
}
exports.runReduceWhileManaged = runReduceWhileManaged
/**
 * Executes an effectful fold over the stream of values.
 * Returns a Managed value that represents the scope of the stream.
 * Stops the fold early when the condition is not fulfilled.
 */
function runReduceWhileManagedM(self, s) {
  return (cont) => (f) => runManaged_(self, SK.reduceM(s)(cont)(f))
}
exports.runReduceWhileManagedM = runReduceWhileManagedM
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 */
function forEach_(self, f) {
  return runForEach_(self, f)
}
exports.forEach_ = forEach_
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 *
 * @dataFirst forEach_
 */
function forEach(f) {
  return (self) => forEach_(self, f)
}
exports.forEach = forEach
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 */
function runForEach_(self, f) {
  return C.run_(self, SK.forEach(f))
}
exports.runForEach_ = runForEach_
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 *
 * @dataFirst runForEach_
 */
function runForEach(f) {
  return (self) => runForEach_(self, f)
}
exports.runForEach = runForEach
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 */
function runForEachChunk_(self, f) {
  return C.run_(self, SK.forEachChunk(f))
}
exports.runForEachChunk_ = runForEachChunk_
/**
 * Consumes all elements of the stream, passing them to the specified callback.
 *
 * @dataFirst runForEachChunk_
 */
function runForEachChunk(f) {
  return (self) => runForEachChunk_(self, f)
}
exports.runForEachChunk = runForEachChunk
/**
 * Like `Stream#forEachChunk`, but returns a `Managed` so the finalization order
 * can be controlled.
 */
function runForEachChunkManaged_(self, f) {
  return runManaged_(self, SK.forEachChunk(f))
}
exports.runForEachChunkManaged_ = runForEachChunkManaged_
/**
 * Like `Stream#forEachChunk`, but returns a `Managed` so the finalization order
 * can be controlled.
 */
function runForEachChunkManaged(f) {
  return (self) => runForEachChunkManaged_(self, f)
}
exports.runForEachChunkManaged = runForEachChunkManaged
/**
 * Like `Stream#forEach`, but returns a `Managed` so the finalization order
 * can be controlled.
 */
function runForEachManaged_(self, f) {
  return runManaged_(self, SK.forEach(f))
}
exports.runForEachManaged_ = runForEachManaged_
/**
 * Like `Stream#forEach`, but returns a `Managed` so the finalization order
 * can be controlled.
 *
 * @dataFirst runForEachManaged_
 */
function runForEachManaged(f) {
  return (self) => runForEachManaged_(self, f)
}
exports.runForEachManaged = runForEachManaged
/**
 * Consumes elements of the stream, passing them to the specified callback,
 * and terminating consumption when the callback returns `false`.
 */
function runForEachWhile_(self, f) {
  return C.run_(self, SK.forEachWhile(f))
}
exports.runForEachWhile_ = runForEachWhile_
/**
 * Consumes elements of the stream, passing them to the specified callback,
 * and terminating consumption when the callback returns `false`.
 *
 * @dataFirst runForEachWhile_
 */
function runForEachWhile(f) {
  return (self) => runForEachWhile_(self, f)
}
exports.runForEachWhile = runForEachWhile
/**
 * Like `Stream#forEachWhile`, but returns a `ZManaged` so the finalization order
 * can be controlled.
 */
function runForEachWhileManaged_(self, f) {
  return runManaged_(self, SK.forEachWhile(f))
}
exports.runForEachWhileManaged_ = runForEachWhileManaged_
/**
 * Like `Stream#forEachWhile`, but returns a `ZManaged` so the finalization order
 * can be controlled.
 *
 * @dataFirst runForEachWhileManaged_
 */
function runForEachWhileManaged(f) {
  return (self) => runForEachWhileManaged_(self, f)
}
exports.runForEachWhileManaged = runForEachWhileManaged
/**
 * Effectfully filters the elements emitted by this stream.
 */
function filterM_(self, f) {
  return C.loopOnPartialChunksElements_(self, (a, emit) =>
    T.chain_(f(a), (r) => (r ? emit(a) : T.unit), fileName_1 + ":1814:13")
  )
}
exports.filterM_ = filterM_
/**
 * Effectfully filters the elements emitted by this stream.
 *
 * @dataFirst filterM_
 */
function filterM(f) {
  return (self) => filterM_(self, f)
}
exports.filterM = filterM
function filterNot_(self, pred) {
  return filter_(self, (a) => !pred(a))
}
exports.filterNot_ = filterNot_
function filterNot(pred) {
  return (self) => filterNot_(self, pred)
}
exports.filterNot = filterNot
/**
 * Emits elements of this stream with a fixed delay in between, regardless of how long it
 * takes to produce a value.
 */
function fixed_(self, duration) {
  return schedule_(self, SC.fixed(duration))
}
exports.fixed_ = fixed_
/**
 * Emits elements of this stream with a fixed delay in between, regardless of how long it
 * takes to produce a value.
 *
 * @dataFirst fixed_
 */
function fixed(duration) {
  return (self) => fixed_(self, duration)
}
exports.fixed = fixed
/**
 * Submerges the chunks carried by this stream into the stream's structure, while
 * still preserving them.
 */
function flattenChunks(self) {
  return new core_1.Stream(CH.mapOut_(self.channel, A.flatten))
}
exports.flattenChunks = flattenChunks
/**
 * Flattens `Exit` values. `Exit.Failure` values translate to stream failures
 * while `Exit.Success` values translate to stream elements.
 */
function flattenExit(self) {
  return C.mapM_(self, (a) => T.done(a, fileName_1 + ":1902:37"))
}
exports.flattenExit = flattenExit
/**
 * Unwraps `Exit` values that also signify end-of-stream by failing with `None`.
 *
 * For `Exit<E, A>` values that do not signal end-of-stream, prefer:
 */
function flattenExitOption(self) {
  const processChunk = (chunk, cont) => {
    const {
      tuple: [toEmit, rest]
    } = A.splitWhere_(chunk, (_) => !Ex.succeeded(_))
    const next = O.fold_(
      A.head(rest),
      () => cont,
      Ex.fold(
        (cause) =>
          O.fold_(
            CS.flipCauseOption(cause),
            () => CH.end(undefined),
            (cause) => CH.halt(cause)
          ),
        () => CH.end(undefined)
      )
    )
    return CH.zipRight_(
      CH.write(
        A.filterMap_(
          toEmit,
          Ex.fold(
            () => O.none,
            (a) => O.some(a)
          )
        )
      ),
      next
    )
  }
  const process = CH.readWithCause(
    (chunk) => processChunk(chunk, process),
    (cause) => CH.halt(cause),
    (_) => CH.end(undefined)
  )
  return new core_1.Stream(self.channel[">>>"](process))
}
exports.flattenExitOption = flattenExitOption
/**
 * Submerges the iterables carried by this stream into the stream's structure, while
 * still preserving them.
 */
function flattenIterables(self) {
  return flattenChunks(C.map_(self, (a) => A.from(a)))
}
exports.flattenIterables = flattenIterables
/**
 * Unwraps `Exit` values and flatten chunks that also signify end-of-stream by failing with `None`.
 */
function flattenTake(self) {
  return flattenChunks(flattenExitOption(C.map_(self, (_) => _.exit)))
}
exports.flattenTake = flattenTake
/**
 * Creates a stream from an effect producing a value of type `A`
 */
function fromEffect(fa) {
  return fromEffectOption(T.mapError_(fa, O.some, fileName_1 + ":2009:38"))
}
exports.fromEffect = fromEffect
/**
 * Creates a stream from an effect producing a value of type `A` or an empty Stream
 */
function fromEffectOption(fa) {
  return new core_1.Stream(
    CH.unwrap(
      T.fold_(
        fa,
        O.fold(
          () => CH.end(undefined),
          (e) => CH.fail(e)
        ),
        (a) => CH.write(A.single(a)),
        fileName_1 + ":2020:14"
      )
    )
  )
}
exports.fromEffectOption = fromEffectOption
/**
 * Transforms the chunks emitted by this stream.
 */
function mapChunks_(self, f) {
  return new core_1.Stream(CH.mapOut_(self.channel, f))
}
exports.mapChunks_ = mapChunks_
/**
 * Transforms the chunks emitted by this stream.
 *
 * @dataFirst mapChunks_
 */
function mapChunks(f) {
  return (self) => mapChunks_(self, f)
}
exports.mapChunks = mapChunks
/**
 * Transforms the errors emitted by this stream using `f`.
 */
function mapError_(self, f) {
  return new core_1.Stream(CH.mapError_(self.channel, f))
}
exports.mapError_ = mapError_
/**
 * Transforms the errors emitted by this stream using `f`.
 *
 * @dataFirst mapError_
 */
function mapError(f) {
  return (self) => mapError_(self, f)
}
exports.mapError = mapError
/**
 * Like `Stream#runIntoHub`, but provides the result as a `Managed` to allow for scope
 * composition.
 */
function runIntoHubManaged_(self, hub) {
  return runIntoManaged_(self, H.toQueue(hub))
}
exports.runIntoHubManaged_ = runIntoHubManaged_
/**
 * Like `Stream#runIntoHub`, but provides the result as a `Managed` to allow for scope
 * composition.
 *
 * @dataFirst runIntoHubManaged_
 */
function runIntoHubManaged(hub) {
  return (self) => runIntoHubManaged_(self, hub)
}
exports.runIntoHubManaged = runIntoHubManaged
/**
 * Like `Stream#into`, but provides the result as a `Managed` to allow for scope
 * composition.
 */
function runIntoManaged_(self, queue) {
  const writer = CH.readWithCause(
    (in_) => CH.zipRight_(CH.write(Take.chunk(in_)), writer),
    (cause) => CH.write(Take.halt(cause)),
    (_) => CH.write(Take.end)
  )
  return M.asUnit(
    CH.runManaged(
      CH.drain(CH.mapOutM_(self.channel[">>>"](writer), (_) => Q.offer_(queue, _)))
    )
  )
}
exports.runIntoManaged_ = runIntoManaged_
/**
 * Like `Stream#into`, but provides the result as a `Managed` to allow for scope
 * composition.
 *
 * @dataFirst runIntoManaged_
 */
function runIntoManaged(queue) {
  return (self) => runIntoManaged_(self, queue)
}
exports.runIntoManaged = runIntoManaged
exports.DEFAULT_CHUNK_SIZE = 4096
/**
 * Converts the stream to a managed hub of chunks. After the managed hub is used,
 * the hub will never again produce values and should be discarded.
 */
function toHub_(self, capacity) {
  return M.map_(
    M.tap_(
      M.bind_(
        M.do,
        "hub",
        () => T.toManagedRelease_(H.makeBounded(capacity), (_) => H.shutdown(_)),
        fileName_1 + ":2148:11"
      ),
      ({ hub }) => M.fork(runIntoHubManaged_(self, hub), fileName_1 + ":2153:30"),
      fileName_1 + ":2153:10"
    ),
    ({ hub }) => hub,
    fileName_1 + ":2154:10"
  )
}
exports.toHub_ = toHub_
/**
 * Converts the stream to a managed hub of chunks. After the managed hub is used,
 * the hub will never again produce values and should be discarded.
 *
 * @dataFirst toHub_
 */
function toHub(capacity) {
  return (self) => toHub_(self, capacity)
}
exports.toHub = toHub
/**
 * Creates a stream from a `XQueue` of values
 */
function fromQueue_(queue, maxChunkSize = exports.DEFAULT_CHUNK_SIZE) {
  return repeatEffectChunkOption(
    T.catchAllCause_(
      T.map_(Q.takeBetween_(queue, 1, maxChunkSize), A.from, fileName_1 + ":2178:12"),
      (c) =>
        T.chain_(
          Q.isShutdown(queue),
          (down) => {
            if (down && CS.interrupted(c)) {
              return Pull.end
            } else {
              return Pull.halt(c)
            }
          },
          fileName_1 + ":2180:17"
        ),
      fileName_1 + ":2179:22"
    )
  )
}
exports.fromQueue_ = fromQueue_
/**
 * Creates a stream from a `XQueue` of values
 */
function fromQueue(maxChunkSize = exports.DEFAULT_CHUNK_SIZE) {
  return (queue) => fromQueue_(queue, maxChunkSize)
}
exports.fromQueue = fromQueue
/**
 * Creates a stream from an effect producing chunks of `A` values until it fails with None.
 */
function repeatEffectChunkOption(fa) {
  return unfoldChunkM(undefined)((_) => {
    return T.catchAll_(
      T.map_(
        fa,
        (chunk) => O.some(Tp.tuple(chunk, undefined)),
        fileName_1 + ":2208:13"
      ),
      O.fold(
        () => T.none,
        (e) => T.fail(e, fileName_1 + ":2211:22")
      ),
      fileName_1 + ":2207:23"
    )
  })
}
exports.repeatEffectChunkOption = repeatEffectChunkOption
/**
 * Creates a stream by effectfully peeling off the "layers" of a value of type `S`
 */
function unfoldChunkM(s) {
  return (f) => {
    const loop = (s) =>
      CH.unwrap(
        T.map_(
          f(s),
          O.fold(
            () => CH.end(undefined),
            ({ tuple: [as, s] }) => CH.zipRight_(CH.write(as), loop(s))
          ),
          fileName_1 + ":2226:15"
        )
      )
    return new core_1.Stream(loop(s))
  }
}
exports.unfoldChunkM = unfoldChunkM
/**
 * Creates a stream by effectfully peeling off the "layers" of a value of type `S`
 */
function unfoldM(s) {
  return (f) => {
    return unfoldChunkM(s)((_) =>
      T.map_(
        f(_),
        O.map(({ tuple: [a, s] }) => Tp.tuple(A.single(a), s)),
        fileName_1 + ":2247:13"
      )
    )
  }
}
exports.unfoldM = unfoldM
/**
 * Converts the stream to a managed queue of chunks. After the managed queue is used,
 * the queue will never again produce values and should be discarded.
 */
function toQueue_(self, capacity = 2) {
  return M.map_(
    M.tap_(
      M.bind_(
        M.do,
        "queue",
        () =>
          T.toManagedRelease_(
            Q.makeBounded(capacity, fileName_1 + ":2266:40"),
            Q.shutdown
          ),
        fileName_1 + ":2265:11"
      ),
      ({ queue }) => M.fork(runIntoManaged_(self, queue), fileName_1 + ":2268:32"),
      fileName_1 + ":2268:10"
    ),
    ({ queue }) => queue,
    fileName_1 + ":2269:10"
  )
}
exports.toQueue_ = toQueue_
/**
 * Converts the stream to a managed queue of chunks. After the managed queue is used,
 * the queue will never again produce values and should be discarded.
 *
 * @dataFirst toQueue_
 */
function toQueue(capacity = 2) {
  return (self) => toQueue_(self, capacity)
}
exports.toQueue = toQueue
/**
 * Converts the stream into an unbounded managed queue. After the managed queue
 * is used, the queue will never again produce values and should be discarded.
 */
function toQueueUnbounded(self) {
  return M.map_(
    M.tap_(
      M.bind_(
        M.do,
        "queue",
        () => T.toManagedRelease_(Q.makeUnbounded(), Q.shutdown),
        fileName_1 + ":2292:11"
      ),
      ({ queue }) => M.fork(runIntoManaged_(self, queue), fileName_1 + ":2295:32"),
      fileName_1 + ":2295:10"
    ),
    ({ queue }) => queue,
    fileName_1 + ":2296:10"
  )
}
exports.toQueueUnbounded = toQueueUnbounded
/**
 * The stream that always halts with `cause`.
 */
function halt(cause) {
  return fromEffect(T.halt(cause, fileName_1 + ":2304:27"))
}
exports.halt = halt
/**
 * Creates a stream from a subscription to a hub.
 */
function fromHub(hub) {
  return C.chain_(C.managed(H.subscribe(hub)), fromQueue())
}
exports.fromHub = fromHub
function runManaged_(self, sink) {
  return CH.runManaged(CH.drain(CH.pipeTo_(self.channel, sink.channel)))
}
exports.runManaged_ = runManaged_
/**
 * @dataFirst runManaged_
 */
function runManaged(sink) {
  return (self) => runManaged_(self, sink)
}
exports.runManaged = runManaged
/**
 * Interrupts the evaluation of this stream when the provided IO completes. The given
 * IO will be forked as part of this stream, and its success will be discarded. This
 * combinator will also interrupt any in-progress element being pulled from upstream.
 *
 * If the IO completes with a failure before the stream completes, the returned stream
 * will emit that failure.
 */
function interruptWhen_(self, io) {
  return new core_1.Stream(CH.interruptWhen_(self.channel, io))
}
exports.interruptWhen_ = interruptWhen_
/**
 * Interrupts the evaluation of this stream when the provided IO completes. The given
 * IO will be forked as part of this stream, and its success will be discarded. This
 * combinator will also interrupt any in-progress element being pulled from upstream.
 *
 * If the IO completes with a failure before the stream completes, the returned stream
 * will emit that failure.
 *
 * @dataFirst interruptWhen_
 */
function interruptWhen(io) {
  return (self) => interruptWhen_(self, io)
}
exports.interruptWhen = interruptWhen
/**
 * Interrupts the evaluation of this stream when the provided promise resolves. This
 * combinator will also interrupt any in-progress element being pulled from upstream.
 *
 * If the promise completes with a failure, the stream will emit that failure.
 */
function interruptWhenP_(self, p) {
  return new core_1.Stream(CH.interruptWhenP_(self.channel, p))
}
exports.interruptWhenP_ = interruptWhenP_
/**
 * Interrupts the evaluation of this stream when the provided promise resolves. This
 * combinator will also interrupt any in-progress element being pulled from upstream.
 *
 * If the promise completes with a failure, the stream will emit that failure.
 *
 * @dataFirst interruptWhenP_
 */
function interruptWhenP(p) {
  return (self) => interruptWhenP_(self, p)
}
exports.interruptWhenP = interruptWhenP
/**
 * Schedules the output of the stream using the provided `schedule`.
 */
function schedule_(self, schedule) {
  return collect_(
    scheduleEither_(self, schedule),
    E.fold(
      (_) => O.none,
      (r) => O.some(r)
    )
  )
}
exports.schedule_ = schedule_
/**
 * Schedules the output of the stream using the provided `schedule`.
 *
 * @dataFirst schedule_
 */
function schedule(schedule) {
  return (self) => schedule_(self, schedule)
}
exports.schedule = schedule
/**
 * Schedules the output of the stream using the provided `schedule` and emits its output at
 * the end (if `schedule` is finite).
 */
function scheduleEither_(self, schedule) {
  return scheduleWith(self, schedule)(
    (r) => E.right(r),
    (l) => E.left(l)
  )
}
exports.scheduleEither_ = scheduleEither_
/**
 * Schedules the output of the stream using the provided `schedule` and emits its output at
 * the end (if `schedule` is finite).
 *
 * @dataFirst scheduleEither_
 */
function scheduleEither(schedule) {
  return (self) => scheduleEither_(self, schedule)
}
exports.scheduleEither = scheduleEither
/**
 * Schedules the output of the stream using the provided `schedule` and emits its output at
 * the end (if `schedule` is finite).
 * Uses the provided function to align the stream and schedule outputs on the same type.
 */
function scheduleWith(self, schedule) {
  return (f, g) =>
    C.unwrap(
      T.map_(
        SC.driver(schedule),
        (driver) =>
          C.loopOnPartialChunksElements_(self, (a, emit) =>
            T.orElse_(
              T.zipRight_(driver.next(a), emit(f(a)), fileName_1 + ":2449:32"),
              () =>
                T.zipLeft(
                  T.chain_(
                    T.orDie(driver.last, fileName_1 + ":2452:22"),
                    (b) => T.zipRight_(emit(f(a)), emit(g(b)), fileName_1 + ":2453:41"),
                    fileName_1 + ":2453:22"
                  ),
                  driver.reset,
                  fileName_1 + ":2454:24"
                ),
              fileName_1 + ":2449:20"
            )
          ),
        fileName_1 + ":2447:13"
      )
    )
}
exports.scheduleWith = scheduleWith
/**
 * Applies the transducer to the stream and emits its outputs.
 */
function transduce_(self, sink) {
  return new core_1.Stream(
    CH.suspend(() => {
      const leftovers = new AtomicReference_1.AtomicReference(A.empty())
      const upstreamDone = new AtomicBoolean_1.AtomicBoolean(false)
      const buffer = CH.suspend(() => {
        const l = leftovers.get
        if (A.isEmpty(l)) {
          return CH.readWith(
            (c) => CH.zipRight_(CH.write(c), buffer),
            (e) => CH.fail(e),
            (done) => CH.end(done)
          )
        } else {
          leftovers.set(A.empty())
          return CH.zipRight_(CH.writeChunk(l), buffer)
        }
      })
      const concatAndGet = (c) => {
        const ls = leftovers.get
        const concat = A.concat_(
          ls,
          A.filter_(c, (a) => !A.isEmpty(a))
        )
        leftovers.set(concat)
        return concat
      }
      const upstreamMarker = CH.readWith(
        (_in) => CH.zipRight_(CH.write(_in), upstreamMarker),
        (err) => CH.fail(err),
        (done) =>
          CH.zipRight_(
            CH.succeedWith(() => upstreamDone.set(true)),
            CH.end(done)
          )
      )
      const transducer = CH.chain_(
        CH.doneCollect(sink.channel),
        ({ tuple: [leftover, z] }) =>
          CH.chain_(
            CH.succeedWith(() => Tp.tuple(upstreamDone.get, concatAndGet(leftover))),
            ({ tuple: [done, newLeftovers] }) => {
              const nextChannel =
                done && A.isEmpty(newLeftovers) ? CH.end(undefined) : transducer
              return CH.zipRight_(CH.write(A.single(z)), nextChannel)
            }
          )
      )
      return self.channel[">>>"](upstreamMarker)[">>>"](buffer)[">>>"](transducer)
    })
  )
}
exports.transduce_ = transduce_
/**
 * Applies the transducer to the stream and emits its outputs.
 *
 * @dataFirst transduce_
 */
function transduce(sink) {
  return (self) => transduce_(self, sink)
}
exports.transduce = transduce
//# sourceMappingURL=api.js.map
