bitty

Package Version Hex Docs

A zero-copy binary parser combinator library for Gleam.

Installation

gleam add bitty

Quick Example

Parsing a simple TLV (tag-length-value) structure

Using Gleam’s use syntax for monadic bind:

import bitty as p
import bitty/bytes as b
import bitty/num

pub type Tlv {
  Tlv(tag: Int, length: Int, value: BitArray)
}

pub fn tlv() -> p.Parser(Tlv) {
  use tag <- p.then(num.u8())
  use len <- p.then(num.u8())
  use value <- p.then(b.take(len))

  p.success(Tlv(tag, len, value))
}

Core Concepts

Parser

pub opaque type Parser(a)

Parsers operate over BitArray and track:

Running a parser

pub fn run(parser: Parser(a), on input: BitArray)
  -> Result(a, BittyError)

pub fn run_partial(parser: Parser(a), on input: BitArray)
  -> Result(#(a, BitArray), BittyError)

Length-Bounded Parsing

Critical for TLV-style formats:

pub fn within_bytes(byte_len: Int, run inner: Parser(a))
  -> Parser(a)

Parse exactly byte_len bytes as a sub-stream.

Used for:

Numeric Decoding

import bitty/num

num.u8()
num.u16(num.BigEndian)
num.u32(num.LittleEndian)
num.u64(num.BigEndian)

All integer parsers return Int. On the JavaScript target, 64-bit values above 2^53 - 1 (9,007,199,254,740,991) may lose precision due to IEEE 754 double-precision floating-point limitations.

Bit-Level Parsing

import bitty/bits

use flag <- p.then(bits.bit())
use value <- p.then(bits.uint(5))
use _ <- p.then(p.align())

p.success(#(flag, value))

Byte-aligned parsing is the fast path. Bit parsing is explicit and opt-in.

Error Reporting

Structured error type:

pub type BittyError {
  BittyError(
    at: Location,
    expected: List(String),
    context: List(String),
    message: Option(String),
  )
}

Add readable labels:

p.label(parser, named: "ASN.1 length")
p.context(parser, in: "TLS handshake")

You get precise error locations and meaningful context stacks.

Search Document