Sign in

    brotli

    A streaming Brotli (RFC 7932) decoder in pure MoonBit: arbitrary input chunks, bounded output slices, memory bounded by the window.

    brotli
    compression
    decompression
    rfc7932
    streaming
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    yesterday
    Downloads
    263

    #gaato/brotli

    A streaming Brotli (RFC 7932) decoder in pure MoonBit. Native, JS, Wasm and Wasm GC.

    moon add gaato/brotli

    Streaming: feed input as it arrives, take output in slices of the size you choose.

    ///|
    fn decode_all(chunks : Array[Bytes], sink : (BytesView) -> Unit) -> Unit raise {
    let decoder = @brotli.Decoder()
    let out = FixedArray::make(64 * 1024, b'\x00')
    for i, chunk in chunks {
    let mut input = chunk[:]
    for ;; {
    let status = decoder.step_into(input, out, end=i == chunks.length() - 1)
    input = input[decoder.last_consumed():]
    sink(Bytes::from_array(out[:decoder.last_produced()]))
    match status {
    Done => return
    NeedMoreInput => break
    NeedMoreOutput => ()
    }
    }
    }
    }

    One shot:

    ///|
    fn example(compressed : Bytes) -> Bytes raise @brotli.BrotliError {
    @brotli.decompress(compressed, max_output=16 * 1024 * 1024)
    }

    #What it does

    • Decodes every RFC 7932 stream, including the static dictionary and its 121 transforms.
    • Takes input in chunks of any size, down to one byte, and writes output into buffers of any size; the same step / Status shape as moonbit-community/flate.
    • Memory is the window (at most 16 MiB, and no more than the output so far) plus tables of at most 1.3 MiB. Decoder(max_window_bits=n) refuses streams that need a window over 2^n bytes.
    • Every malformed stream raises BrotliError(kind, message): Truncated, Corrupt, TrailingData (bytes after the stream), WindowTooLarge or OutputLimitExceeded. It does not abort.

    Not included: an encoder, and the non-RFC large-window format.

    #License

    Apache-2.0. The static dictionary in src/static_data.mbt comes from google/brotli under the MIT license; see LICENSE-dictionary.

    BrotliError

    pub suberror BrotliError {
    BrotliError(BrotliErrorKind, String)
    } derive(
    Debug
    )

    The error every decoding failure raises: a kind and a message.

    BrotliErrorKind

    pub(all) enum BrotliErrorKind {
    Truncated
    Corrupt
    TrailingData
    WindowTooLarge
    OutputLimitExceeded
    } derive(Eq,
    Debug
    )

    Why a stream was refused.

    BrotliErrorKind::equal

    BrotliErrorKind::not_equal

    fn BrotliErrorKind::not_equal(x : BrotliErrorKind, y : BrotliErrorKind) -> Bool

    Decoder

    pub struct Decoder {
    // private fields
    }

    A streaming Brotli decoder (RFC 7932). Feed it input in chunks of any size with step and collect output in slices of any size; it keeps the sliding window (at most 16 MiB, and no more than the output so far) plus fixed-size tables, never the whole input or output.

    Decoder::Decoder

    fn Decoder::Decoder(max_window_bits? : Int) -> Decoder

    A decoder at the start of a stream. It refuses, with WindowTooLarge, a stream whose window exceeds 1 << max_window_bits bytes (the window memory it would need); the default 24 accepts every RFC 7932 stream. Values are clamped to 10..24.

    Decoder::is_finished

    fn Decoder::is_finished(self : Decoder) -> Bool

    Whether the stream has ended and all its output has been handed out.

    Decoder::last_consumed

    fn Decoder::last_consumed(self : Decoder) -> Int

    Input bytes the latest step accepted: all of them on NeedMoreInput. Zero after a step that raised.

    Decoder::last_produced

    fn Decoder::last_produced(self : Decoder) -> Int

    Output bytes the latest step wrote. Zero after a step that raised.

    Decoder::reset

    fn Decoder::reset(self : Decoder) -> Unit

    Starts a new stream, keeping the tables' memory. The window is released.

    Decoder::step

    fn Decoder::step(self : Decoder, input : BytesView, output : MutArrayView[Byte], end? : Bool) -> Status raise BrotliError

    Decodes from input into output; see last_consumed and last_produced for how much of each it used. Pass end=true once input holds the last bytes of the stream, so that a stream cut short raises Truncated instead of asking for more. Bytes after the end of the stream raise TrailingData. After an error the decoder raises it again until reset.

    Decoder::step_into

    fn Decoder::step_into(self : Decoder, input : BytesView, output : FixedArray[Byte], end? : Bool) -> Status raise BrotliError

    step into a whole FixedArray, with bulk copies.

    Status

    pub(all) enum Status {
    Done
    NeedMoreInput
    NeedMoreOutput
    } derive(Eq,
    Debug
    )

    Outcome of one Decoder::step, as in moonbit-community/flate.

    Status::equal

    fn Status::equal(Status, Status) -> Bool

    Status::not_equal

    fn Status::not_equal(x : Status, y : Status) -> Bool

    Status::to_repr

    decompress

    fn decompress(input : BytesView, max_output? : Int, max_window_bits? : Int) -> Bytes raise BrotliError

    Decodes a whole Brotli stream held in memory. max_output caps the decoded size (unlimited by default) and raises OutputLimitExceeded past it; max_window_bits is as for Decoder.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io