Decode the protobuf wire format in Gleam! protobin.hexdocs.pm/
gleam protobuf
3

Configure Feed

Select the types of activity you want to include in your feed.

Add byte decoder

eaon (Feb 24, 2026, 3:12 PM EST) c942b6f8 541cbcc1

+50
+9
src/protobin.gleam
··· 346 346 single_or_raw(of: decode.bit_array, named: "BitArray", default: <<>>) 347 347 } 348 348 349 + /// Decode a `bytes` field. The result is guaranteed to be byte-aligned. 350 + pub fn decode_bytes() -> Decoder(BitArray) { 351 + use bits <- decode.then(single_or_raw_bit_array()) 352 + case bits { 353 + <<_:bytes>> -> decode.success(bits) 354 + _ -> decode.failure(<<>>, "Bytes") 355 + } 356 + } 357 + 349 358 pub fn decode_protobuf( 350 359 // Passed as a function so recursive decoders are easier 351 360 using decoder: fn() -> Decoder(t),
+41
test/protobin_test.gleam
··· 282 282 ) 283 283 } 284 284 285 + type BytesFields { 286 + BytesFields(data: BitArray, tag: BitArray) 287 + } 288 + 289 + fn bytes_fields_decoder() -> Decoder(BytesFields) { 290 + use data <- decode.field(3, protobin.decode_bytes()) 291 + use tag <- decode.field(9, protobin.decode_bytes()) 292 + BytesFields(data:, tag:) |> decode.success 293 + } 294 + 295 + pub fn bytes_fields_test() { 296 + let bits = << 297 + // field 3 298 + 0x1a, 299 + 0x03, 300 + 0x01, 301 + 0x02, 302 + 0x03, 303 + // field 9 304 + 0x4a, 305 + 0x04, 306 + 0x0a, 307 + 0x0b, 308 + 0x0c, 309 + 0x0d, 310 + >> 311 + let assert Ok(parsed) = parse(from: bits, using: bytes_fields_decoder()) 312 + 313 + assert parsed 314 + == Parsed( 315 + value: BytesFields(data: <<0x01, 0x02, 0x03>>, tag: << 316 + 0x0a, 317 + 0x0b, 318 + 0x0c, 319 + 0x0d, 320 + >>), 321 + rest: <<>>, 322 + pos: 11, 323 + ) 324 + } 325 + 285 326 pub fn does_not_ignore_groups_test() { 286 327 let path = "./test/ignores-groups.pb" 287 328 let assert Ok(bits) = file.read_bits(from: path)