"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.zipLeft =
  exports.zipLeft_ =
  exports.zipRight =
  exports.zipRight_ =
  exports.zip =
  exports.zip_ =
  exports.zipWith =
  exports.zipWith_ =
    void 0
const tracing_1 = __importStar(require("../../../Tracing"))
const fileName_1 = "(@effect-ts/system): _src/Experimental/Stream/_internal/zip.ts"
const Cause = __importStar(require("../../../Cause"))
const Chunk = __importStar(require("../../../Collections/Immutable/Chunk"))
const Tp = __importStar(require("../../../Collections/Immutable/Tuple"))
const T = __importStar(require("../../../Effect"))
const E = __importStar(require("../../../Either"))
const Exit = __importStar(require("../../../Exit"))
const O = __importStar(require("../../../Option"))
const S = __importStar(require("./core"))
const utils_1 = require("./utils")
class Running {
  constructor(excess) {
    this.excess = excess
    this._tag = "Running"
  }
}
class LeftDone {
  constructor(excessL) {
    this.excessL = excessL
    this._tag = "LeftDone"
  }
}
class RightDone {
  constructor(excessR) {
    this.excessR = excessR
    this._tag = "RightDone"
  }
}
class End {
  constructor() {
    this._tag = "End"
  }
}
function handleSuccess(f, leftUpd, rightUpd, excess) {
  const [leftExcess, rightExcess] = E.fold_(
    excess,
    (l) => [l, Chunk.empty()],
    (r) => [Chunk.empty(), r]
  )
  const left = O.fold_(
    leftUpd,
    () => leftExcess,
    (upd) => Chunk.concat_(leftExcess, upd)
  )
  const right = O.fold_(
    rightUpd,
    () => rightExcess,
    (upd) => Chunk.concat_(rightExcess, upd)
  )
  const {
    tuple: [emit, newExcess]
  } = (0, utils_1.zipChunks_)(left, right, f)
  if (leftUpd._tag === "Some" && rightUpd._tag === "Some") {
    return Exit.succeed(Tp.tuple(emit, new Running(newExcess)))
  }
  if (leftUpd._tag === "None" && rightUpd._tag === "None") {
    return Exit.fail(O.none)
  }
  const newState =
    newExcess._tag === "Left"
      ? Chunk.isEmpty(newExcess.left)
        ? new End()
        : new LeftDone(newExcess.left)
      : Chunk.isEmpty(newExcess.right)
      ? new End()
      : new RightDone(newExcess.right)
  return Exit.succeed(Tp.tuple(emit, newState))
}
/**
 * Zips this stream with another point-wise and applies the function to the paired elements.
 *
 * The new stream will end when one of the sides ends.
 */
function zipWith_(self, that, f) {
  return S.combineChunks_(
    self,
    that,
    new Running(E.left(Chunk.empty())),
    (st, p1, p2) => {
      switch (st._tag) {
        case "End": {
          return T.succeed(Exit.fail(O.none), fileName_1 + ":87:27")
        }
        case "Running": {
          return T.catchAllCause_(
            T.zipWithPar_(
              T.optional(p1, fileName_1 + ":91:37"),
              T.optional(p2, fileName_1 + ":91:53"),
              (l, r) => handleSuccess(f, l, r, st.excess),
              fileName_1 + ":91:26"
            ),
            (e) => T.succeed(Exit.halt(Cause.map_(e, O.some)), fileName_1 + ":94:29"),
            fileName_1 + ":90:34"
          )
        }
        case "LeftDone": {
          return T.catchAllCause_(
            T.map_(
              T.optional(p2, fileName_1 + ":99:30"),
              (l) => handleSuccess(f, O.none, l, E.left(st.excessL)),
              fileName_1 + ":99:19"
            ),
            (e) => T.succeed(Exit.halt(Cause.map_(e, O.some)), fileName_1 + ":102:29"),
            fileName_1 + ":98:34"
          )
        }
        case "RightDone": {
          return T.catchAllCause_(
            T.map_(
              T.optional(p1, fileName_1 + ":107:30"),
              (r) => handleSuccess(f, r, O.none, E.right(st.excessR)),
              fileName_1 + ":107:19"
            ),
            (e) => T.succeed(Exit.halt(Cause.map_(e, O.some)), fileName_1 + ":110:29"),
            fileName_1 + ":106:34"
          )
        }
      }
    }
  )
}
exports.zipWith_ = zipWith_
/**
 * Zips this stream with another point-wise and applies the function to the paired elements.
 *
 * The new stream will end when one of the sides ends.
 *
 * @dataFirst zipWith_
 */
function zipWith(that, f) {
  return (self) => zipWith_(self, that, f)
}
exports.zipWith = zipWith
/**
 * Zips this stream with another point-wise and emits tuples of elements from both streams.
 *
 * The new stream will end when one of the sides ends.
 */
function zip_(self, that) {
  return zipWith_(self, that, Tp.tuple)
}
exports.zip_ = zip_
/**
 * Zips this stream with another point-wise and emits tuples of elements from both streams.
 *
 * The new stream will end when one of the sides ends.
 *
 * @dataFirst zip_
 */
function zip(that) {
  return (self) => zip_(self, that)
}
exports.zip = zip
/**
 * Zips this stream with another point-wise, but keeps only the outputs of the other stream.
 *
 * The new stream will end when one of the sides ends.
 */
function zipRight_(self, that) {
  return zipWith_(self, that, (_, o) => o)
}
exports.zipRight_ = zipRight_
/**
 * Zips this stream with another point-wise, but keeps only the outputs of the other stream.
 *
 * The new stream will end when one of the sides ends.
 *
 * @dataFirst zipRight_
 */
function zipRight(that) {
  return (self) => zipRight_(self, that)
}
exports.zipRight = zipRight
/**
 * Zips this stream with another point-wise, but keeps only the outputs of this stream.
 *
 * The new stream will end when one of the sides ends.
 */
function zipLeft_(self, that) {
  return zipWith_(self, that, (o, _) => o)
}
exports.zipLeft_ = zipLeft_
/**
 * Zips this stream with another point-wise, but keeps only the outputs of this stream.
 *
 * The new stream will end when one of the sides ends.
 *
 * @dataFirst zipLeft_
 */
function zipLeft(that) {
  return (self) => zipLeft_(self, that)
}
exports.zipLeft = zipLeft
//# sourceMappingURL=zip.js.map
