All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zio.stream.Deflate.scala Maven / Gradle / Ivy

There is a newer version: 2.1.13
Show newest version
package zio.stream

import zio.stacktracer.TracingImplicits.disableAutoTrace
import zio.stream.compression.{CompressionLevel, CompressionStrategy, FlushMode}
import zio.{Chunk, ZIO, Trace}

import java.util.zip.Deflater
import java.{util => ju}
import scala.annotation.tailrec

private object Deflate {
  def makeDeflater[Err, Done](
    bufferSize: Int = 64 * 1024,
    noWrap: Boolean = false,
    level: CompressionLevel = CompressionLevel.DefaultCompression,
    strategy: CompressionStrategy = CompressionStrategy.DefaultStrategy,
    flushMode: FlushMode = FlushMode.NoFlush
  )(implicit trace: Trace): ZChannel[Any, Err, Chunk[Byte], Done, Err, Chunk[Byte], Done] =
    ZChannel.unwrapScoped {
      ZIO
        .acquireRelease(ZIO.succeed {
          val deflater = new Deflater(level.jValue, noWrap)
          deflater.setStrategy(strategy.jValue)
          (deflater, new Array[Byte](bufferSize))
        }) { case (deflater, _) =>
          ZIO.succeed(deflater.end())
        }
        .map {
          case (deflater, buffer) => {

            lazy val loop: ZChannel[Any, Err, Chunk[Byte], Done, Err, Chunk[Byte], Done] =
              ZChannel.readWithCause(
                chunk =>
                  ZChannel.succeed {
                    deflater.setInput(chunk.toArray)
                    pullOutput(deflater, buffer, flushMode)
                  }.flatMap(chunk => ZChannel.write(chunk) *> loop),
                ZChannel.failCause(_),
                done =>
                  ZChannel.succeed {
                    deflater.finish()
                    val out = pullOutput(deflater, buffer, flushMode)
                    deflater.reset()
                    out
                  }.flatMap(chunk => ZChannel.write(chunk).as(done))
              )

            loop
          }
        }
    }

  private def pullOutput(deflater: Deflater, buffer: Array[Byte], flushMode: FlushMode): Chunk[Byte] = {
    @tailrec
    def next(acc: Chunk[Byte]): Chunk[Byte] = {
      val size    = deflater.deflate(buffer, 0, buffer.length, flushMode.jValue)
      val current = Chunk.fromArray(ju.Arrays.copyOf(buffer, size))
      if (current.isEmpty) acc
      else next(acc ++ current)
    }

    next(Chunk.empty)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy