Sign in

    compress

    Compression library for MoonBit: flate, gzip, zlib, lzw, bzip2, snappy, lz4, zstd, brotli

    compression
    deflate
    gzip
    zlib
    lzw
    bzip2
    snappy
    lz4
    zstd
    zstandard
    brotli
    Download zip
    Author
    Version
    0.3.4
    License
    Apache-2.0
    Last updated
    6 months ago
    Downloads
    2K

    Dependencies

    #bikallem/compress

    A pure MoonBit compression library supporting DEFLATE, gzip, zlib, LZW, bzip2, Brotli, Zstandard, and LZ4. Targets native (Linux, Windows, macOS), JavaScript, and WebAssembly.

    #Features

    • Pure MoonBit — no FFI required (optional native acceleration for blit/checksum)
    • Multi-target: native, js, and wasm-gc backends
    • Dynamic Huffman coding with optimal fixed/dynamic block selection
    • Level-differentiated compression: fast greedy (1-3), lazy matching (4-9)
    • SA-IS suffix array construction for O(n) bzip2 BWT
    • Hardware-accelerated CRC-32 (PCLMULQDQ) and Adler-32 (SSSE3) on native, software fallback elsewhere
    • Two-level Huffman table decompression with zero-copy direct output
    • BytesView-based streaming API — zero-copy input slicing
    • Signal protocol streaming — no callbacks, no trait objects, explicit control flow
    • Async streaming for DEFLATE via MoonBit's async/io
    • Cross-validated against Go's compress/* stdlib where applicable, plus external golden vectors for additional formats

    #Table of Contents

    #Packages

    PackageDescription
    bikallem/compress/flateDEFLATE compression/decompression (RFC 1951)
    bikallem/compress/flate/asyncAsync DEFLATE streaming via @io.Reader/@io.Writer
    bikallem/compress/gzipgzip format (RFC 1952)
    bikallem/compress/zlibzlib format (RFC 1950)
    bikallem/compress/lzwLempel-Ziv-Welch (GIF/TIFF/PDF)
    bikallem/compress/brotliBrotli compression/decompression (RFC 7932)
    bikallem/compress/bzip2bzip2 compression/decompression
    bikallem/compress/zstdExperimental Zstandard frame compression/decompression with dictionary support
    bikallem/compress/lz4LZ4 frame compression/decompression for independent-block frames
    bikallem/compress/checksumCRC-32 and Adler-32 checksums

    #Installation

    moon add bikallem/compress

    #Quick Start

    Every package provides one-shot compress/decompress functions for simple use cases:

    // DEFLATE (level defaults to DefaultCompression)
    let compressed = @flate.compress(data)
    let compressed = @flate.compress(data, level=BestSpeed)
    let decompressed = @flate.decompress(compressed)

    // gzip
    let compressed = @gzip.compress(data)
    let compressed = @gzip.compress(data, level=BestCompression, header={ name: "data.txt", ..Header::default() })
    let (decompressed, header) = @gzip.decompress(compressed)

    // zlib (supports preset dictionaries)
    let compressed = @zlib.compress(data)
    let compressed = @zlib.compress(data, dict=my_dict, level=BestSpeed)
    let decompressed = @zlib.decompress(compressed)

    // LZW
    let compressed = @lzw.compress(data, LSB, 8)
    let decompressed = @lzw.decompress(compressed, LSB, 8)

    // Brotli (level 0-11)
    let compressed = @brotli.compress(data)
    let compressed = @brotli.compress(data, level=Level(1))
    let decompressed = @brotli.decompress(compressed)

    // bzip2 (level 1-9, controls block size)
    let compressed = @bzip2.compress(data)
    let compressed = @bzip2.compress(data, level=9)
    let decompressed = @bzip2.decompress(compressed)

    // Zstandard
    let compressed = @zstd.compress(data)
    let compressed = @zstd.compress(data, level=Fast)
    let compressed = @zstd.compress(data, dict=my_zstd_dict)
    let decompressed = @zstd.decompress(compressed)
    let decompressed = @zstd.decompress(compressed, dict=my_zstd_dict)

    // LZ4 (independent-block frames)
    let compressed = @lz4.compress(data)
    let decompressed = @lz4.decompress(compressed)

    // Checksums
    let crc = @checksum.crc32(data[:])
    let adler = @checksum.adler32(data[:])

    #Streaming API

    All packages provide Deflater (compressor) and Inflater (decompressor) types with a signal-protocol interface. flate, gzip, zlib, lzw, bzip2, brotli, and zstd stream incrementally. snappy and lz4 currently use buffered wrappers: they accept chunked input, but decompression waits for a complete stream/frame and compression emits output on finalization.

    #Compression

    Feed data with encode(Some(chunk[:])), finalize with encode(None):

    let d = @flate.Deflater::new(level=BestSpeed)
    match d.encode(Some(data[:])) {
    Ok => () // input buffered, no output yet
    Data(out) => ... // compressed output ready
    End => ... // shouldn't happen mid-stream
    Error(e) => ... // compression error
    }
    loop d.encode(None) {
    Data(out) => { write(out); continue d.encode(None) }
    End => break
    Ok | Error(_) => break
    }

    #Decompression

    Feed compressed data with src(chunk[:]), pull output with decode():

    let d = @flate.Inflater::new()
    d.src(compressed_chunk[:])
    loop d.decode() {
    Await => { d.src(next_chunk[:]); continue d.decode() }
    Data(out) => { write(out); continue d.decode() }
    End => break
    Error(e) => ...
    }

    #Format Wrappers

    gzip and zlib deflaters/inflaters handle headers, checksums, and trailers automatically:

    // gzip with custom header
    let d = @gzip.Deflater::new(header={ name: "data.txt", ..Header::default() })
    // Access the header after decompression
    let header = inflater.header()

    // zlib with preset dictionary
    let d = @zlib.Deflater::new(dict=my_dict)
    let i = @zlib.Inflater::new(dict=my_dict)

    // LZW with bit order and literal width
    let d = @lzw.Deflater::new(MSB, 8)
    let i = @lzw.Inflater::new(MSB, 8)

    // Brotli
    let d = @brotli.Deflater::new(level=Level(6))
    let i = @brotli.Inflater::new()

    // bzip2
    let d = @bzip2.Deflater::new(level=9)
    let i = @bzip2.Inflater::new()

    // Zstandard
    let d = @zstd.Deflater::new(level=Fast, dict=my_zstd_dict)
    let i = @zstd.Inflater::new(dict=my_zstd_dict)

    // LZ4 (buffered wrapper, independent-block frames only)
    let d = @lz4.Deflater::new()
    let i = @lz4.Inflater::new()

    // Get remaining unprocessed input after decompression
    let leftover = inflater.remaining()

    #Async Streaming

    The flate/async package provides async wrappers that work with MoonBit's @io.Reader and @io.Writer interfaces:

    // Async DEFLATE compression
    async fn compress_stream(reader : &@io.Reader, writer : &@io.Writer) -> Unit {
    @flate.async.compress(reader, writer, level=BestSpeed)
    }

    // Async DEFLATE decompression
    async fn decompress_stream(reader : &@io.Reader, writer : &@io.Writer) -> Unit {
    @flate.async.decompress(reader, writer)
    }

    #Compression Levels

    DEFLATE, gzip, and zlib support compression levels via @flate.CompressionLevel:

    LevelDescription
    NoCompressionStore blocks only (level 0)
    BestSpeedFastest compression (level 1)
    Level(2..8)Trade-off between speed and ratio
    BestCompressionSmallest output (level 9)
    DefaultCompressionBalanced default (level 6)
    HuffmanOnlyHuffman encoding, no LZ77 matching

    bzip2 uses its own level parameter (1-9), controlling block size (N x 100KB).

    Brotli uses @brotli.CompressionLevel: Level(0) through Level(11), Default (level 6), or Best (level 11). Higher levels use longer hash chains for better compression ratios.

    Zstandard uses @zstd.CompressionLevel: Fast, Default, Best, or Level(Int).

    Zstandard status: The current codec supports raw, RLE, Huffman-compressed, and treeless literals plus predefined, RLE, repeat, and custom FSE sequence tables. Raw-content and formatted dictionaries are supported for decoding, one-shot compression can emit dictionary IDs for formatted dictionaries, and the Deflater/Inflater wrappers now process frames incrementally. Compression is still an experimental subset encoder rather than a full parity implementation of upstream zstd.

    Brotli features: The decoder is fully RFC 7932 compliant, including the 122KB static dictionary with 121 word transforms. The encoder supports context modeling (level 5+), which uses the previous byte to select among multiple literal Huffman trees for better compression of structured text. Block splitting and static dictionary compression by the encoder are not yet implemented. Quality levels 10-11 use the same hash-chain algorithm as level 9. Output is verified against Go's andybalholm/brotli reference decoder.

    #Checksums

    Stateful hashers implement the Hasher trait for incremental updates:

    let h = @checksum.CRC32::new()
    h.update(chunk1[:])
    h.update(chunk2[:])
    let result = h.checksum()

    #Performance

    Benchmarked on the native backend against Go's standard library (v0.1.2). Ratio < 1 means MoonBit is faster.

    Run benchmarks: ./tools/bench.sh --go

    #DEFLATE

    BenchmarkMoonBitGoRatio
    compress 1 KB16 µs67 µs0.24x
    compress 10 KB63 µs124 µs0.51x
    compress 100 KB570 µs298 µs1.91x
    compress 1 MB6.2 ms2.0 ms3.06x
    compress speed 1 KB12 µs134 µs0.09x
    compress speed 10 KB15 µs125 µs0.12x
    decompress 1 KB0.82 µs4.0 µs0.21x
    decompress 10 KB5.1 µs10.7 µs0.47x
    decompress 100 KB29 µs58 µs0.50x
    decompress 1 MB305 µs915 µs0.33x
    decompress 10 MB4.8 ms10.5 ms0.46x

    Decompression is 2-5x faster than Go at all sizes. BestSpeed compression is 8-11x faster. Default compression is faster up to 10 KB; at larger sizes Go's more aggressive match-finding gives it an edge.

    #bzip2

    BenchmarkMoonBitGoRatio
    compress 1 KB54 µs754 µs0.07x
    compress 10 KB500 µs2,047 µs0.24x
    compress 100 KB5.4 ms10.2 ms0.53x
    compress 1 MB107 ms112 ms0.95x
    decompress 1 KB123 µs420 µs0.29x
    decompress 10 KB167 µs541 µs0.31x
    decompress 100 KB680 µs1,225 µs0.55x
    decompress 1 MB6.0 ms7.2 ms0.83x

    bzip2 uses SA-IS (O(n) suffix array construction) for the Burrows-Wheeler Transform. Go's benchmark uses the system bzip2 binary (C) for compression and Go's compress/bzip2 for decompression.

    #LZW

    BenchmarkMoonBitGoRatio
    compress 1 KB7.4 µs8.6 µs0.86x
    compress 10 KB41 µs42 µs0.98x
    compress 100 KB424 µs427 µs0.99x
    compress 1 MB4.6 ms4.3 ms1.05x
    decompress 1 KB3.7 µs4.7 µs0.78x
    decompress 10 KB16 µs26 µs0.63x
    decompress 100 KB140 µs244 µs0.57x
    decompress 1 MB1.6 ms2.7 ms0.57x

    LZW compression is at parity with Go. Decompression is 1.3-1.8x faster.

    #License

    Apache-2.0