moonframing

    Backend-neutral incremental byte-stream framing for MoonBit

    streaming
    framing
    codec
    protocol
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    10 hours ago
    Downloads
    2

    #MoonFraming

    MoonFraming is a pure-MoonBit framing toolkit for protocols that run over arbitrary byte streams. It separates message boundaries from transport I/O, handles fragmented and coalesced input, enforces resource limits before payload allocation, and can attach CRC-32 corruption detection.

    #Highlights

    • Unsigned LEB128 length prefixes with a five-byte bound
    • One-shot and incremental decoders
    • Correct handling of one-byte fragments and multiple frames per chunk
    • Configurable maximum frame and buffered-input sizes
    • Explicit truncated, malformed, oversized, and checksum failures
    • Optional IEEE CRC-32 protected frames
    • Decoder reset at application-defined resynchronization boundaries
    • Cross-backend CI for Wasm, Wasm-GC, and JavaScript

    #Run

    moon test --deny-warn moon run cmd/main

    #Library example

    ///|
    test {
    let decoder = @moonframing.Decoder::new(max_frame_size=4096)
    let wire = @moonframing.encode_frame(b"hello")
    match decoder.feed(wire) {
    Ok(frames) => assert_true(frames[0] == b"hello")
    Err(_) => fail("valid frame")
    }
    }

    #Protocol

    The base wire format is uLEB128(payload_length) || payload. A checked frame uses uLEB128(payload_length + 4) || payload || crc32_be. The length prefix is limited to five bytes and the decoder checks the configured payload limit as soon as the prefix is complete.

    MoonFraming is not a socket or filesystem library. It is designed to compose with MoonBit async readers, files, WebSockets, RPC transports, and parsers without forcing any particular I/O runtime.

    Licensed under Apache-2.0.

    Decoder

    pub struct Decoder {
    buffer : Array[Byte]
    max_frame_size : Int
    max_buffer_size : Int
    }

    Stateful decoder accepting arbitrarily fragmented byte chunks.

    Decoder::buffered

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

    Number of bytes retained while waiting for a complete frame.

    Decoder::feed

    fn Decoder::feed(self : Decoder, chunk : Bytes) -> Result[Array[Bytes], FrameError]

    Feed any chunk size and return every complete frame now available.

    Decoder::finish

    fn Decoder::finish(self : Decoder) -> Result[Unit, FrameError]

    Signal end-of-input. A partial header or payload is an explicit error.

    Decoder::new

    fn Decoder::new(max_frame_size? : Int, max_buffer_size? : Int) -> Decoder

    Decoder::reset

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

    Discard partial data so a caller can recover at a known boundary.

    FrameError

    pub enum FrameError {
    NeedMore
    MalformedVarint
    FrameTooLarge(Int, Int)
    MissingChecksum
    ChecksumMismatch(UInt, UInt)
    BufferLimitExceeded(Int, Int)
    }

    Deterministic failures returned by frame parsing.

    crc32

    fn crc32(data : Bytes) -> UInt

    IEEE CRC-32 for optional corruption detection on framed transports.

    decode_all

    fn decode_all(data : Bytes, max_frame_size? : Int) -> Result[Array[Bytes], FrameError]

    Decode an entire finite stream and reject trailing partial data.

    decode_checked_frame

    fn decode_checked_frame(data : Bytes, max_frame_size? : Int) -> Result[(Bytes, Int), FrameError]

    Decode and verify one checksummed frame.

    decode_frame

    fn decode_frame(data : Bytes, max_frame_size? : Int) -> Result[(Bytes, Int), FrameError]

    Decode one complete frame and report total bytes consumed.

    decode_varint

    fn decode_varint(data : Bytes, offset? : Int) -> (Int, Int)?

    Decode one unsigned LEB128 value, returning value and bytes consumed.

    encode_checked_frame

    fn encode_checked_frame(payload : Bytes) -> Bytes

    Encode payload plus a big-endian CRC-32 inside the length envelope.

    encode_frame

    fn encode_frame(payload : Bytes) -> Bytes

    Prefix a payload with its unsigned LEB128 byte length.

    encode_frames

    fn encode_frames(payloads : ArrayView[Bytes]) -> Bytes

    Encode several payloads as one concatenated framed stream.

    encode_varint

    fn encode_varint(value : Int) -> Bytes

    Encode a non-negative length as unsigned LEB128 (maximum 31 bits).

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io