Pular para o conteúdo

Stdlib · extensões

compress

compressão (codecs streaming)

extensions.md · 80 linhas · 2 min de leitura

use compress

Codecs de compressão como fluxos: cada um satisfaz Readable/Writeable (io), então compõe com io.copy e bufferização sem materializar tudo. DEFLATE/gzip/zlib são formatos frozen (RFCs de décadas), daí tier 0; brotli/zstd são mais novos, daí tier 1 (adição ao mesmo pacote). O consumidor imediato é o http.auto_decompress (que só os orquestra, como net/TLS faz com crypto).

Comprimir é envolver um Writeable de destino; descomprimir é envolver um Readable de origem. É o mesmo padrão dos adaptadores de io (BufWriter.over, tee):

// gzip (tier 0)
fn (GzipWriter) over(dst: Writeable) -> GzipWriter // escrever nele comprime para 'dst'
fn (w: *GzipWriter) write(data: []byte) -> error{Io}
fn (w: *GzipWriter) flush() -> error{Io}
fn (w: *GzipWriter) close() -> error{Io} // emite o trailer; NÃO fecha 'dst'
fn (GzipReader) over(src: Readable) -> Result[GzipReader, error{Malformed}] // ler dele descomprime 'src'
fn (r: *GzipReader) read(buf: mut []byte) -> Result[usize, error{Malformed, Io}] // Ok(0) = fim
decl GzipWriter { ... } // Writeable + Closeable
decl GzipReader { ... } // Readable

deflate (cru, sem header) e zlib (deflate + header/adler32) têm a mesma forma: DeflateWriter/ DeflateReader, ZlibWriter/ZlibReader. O nível de compressão é opção na construção:

fn (GzipWriter) with_level(dst: Writeable, level: Level) -> GzipWriter
decl Level { Fast; Default; Best; None } // None = store (sem compressão, só envelopa)

One-shot (bufferbuffer) para o caso pequeno, sobre os codecs streaming:

fn gzip(data: []byte) -> []byte // comprime tudo (aloca)
fn gunzip(data: []byte) -> Result[[]byte, error{Malformed}] // descomprime tudo
fn deflate(data: []byte) -> []byte
fn inflate(data: []byte) -> Result[[]byte, error{Malformed}]
use compress
// streaming: arquivo → arquivo, comprimindo, sem carregar na memória
src := fs.open("dump.sql") catch |e| { return e }
out := fs.create("dump.sql.gz") catch |e| { return e }
gz := compress.GzipWriter.over(out)
defer gz.close()
io.copy(gz, src) catch |e| { return e } // bombeia comprimindo

Mesma forma (BrotliReader/BrotliWriter, ZstdReader/ZstdWriter, one-shots brotli/unbrotli/ zstd/unzstd), como adição tier 1 ao pacote, já que giram mais que os formatos clássicos. zstd adiciona dicionários (treino para payloads pequenos repetitivos), a feature que justifica tê-lo:

fn (ZstdWriter) with_dict(dst: Writeable, dict: []byte) -> ZstdWriter // compressão com dicionário
fn zstd_train(samples: []const []byte, dict_size: usize) -> []byte // treina um dicionário
  • Pacote próprio, não dentro de encoding. encoding é representação estrutural (de/para) (Serializable, JSON, base64); compress é transformação de bytes opaca. Conceitos distintos, lares distintos.
  • Tier por formato: DEFLATE/gzip/zlib (frozen, RFC 1950 a 1952) tier 0; brotli/zstd tier 1. O http só precisa dos clássicos.
  • Codecs são fluxos (Readable/Writeable): compõem com io.copy/buffering, streaming por default; one-shots são conveniência por cima.
  • close() não fecha o destino: o wrapper emite seu trailer e devolve; quem é dono de dst/src o fecha (composição, como o resto de io). Sem allocator nas assinaturas (colorless).