From c942b6f8edb182e0079dd69bbfc44bf70a18c5ea Mon Sep 17 00:00:00 2001 From: eaon Date: Tue, 24 Feb 2026 20:12:16 +0000 Subject: [PATCH] Add byte decoder --- src/protobin.gleam | 9 +++++++++ test/protobin_test.gleam | 41 +++++++++++++++++++++++++++++++++++++++++ 2 file(s) changed, 50 insertion(s)(+), 0 deletion(s)(-) diff --git a/src/protobin.gleam b/src/protobin.gleam --- a/src/protobin.gleam +++ b/src/protobin.gleam @@ -346,6 +346,15 @@ single_or_raw(of: decode.bit_array, named: "BitArray", default: <<>>) } +/// Decode a `bytes` field. The result is guaranteed to be byte-aligned. +pub fn decode_bytes() -> Decoder(BitArray) { + use bits <- decode.then(single_or_raw_bit_array()) + case bits { + <<_:bytes>> -> decode.success(bits) + _ -> decode.failure(<<>>, "Bytes") + } +} + pub fn decode_protobuf( // Passed as a function so recursive decoders are easier using decoder: fn() -> Decoder(t), diff --git a/test/protobin_test.gleam b/test/protobin_test.gleam --- a/test/protobin_test.gleam +++ b/test/protobin_test.gleam @@ -282,6 +282,47 @@ ) } +type BytesFields { + BytesFields(data: BitArray, tag: BitArray) +} + +fn bytes_fields_decoder() -> Decoder(BytesFields) { + use data <- decode.field(3, protobin.decode_bytes()) + use tag <- decode.field(9, protobin.decode_bytes()) + BytesFields(data:, tag:) |> decode.success +} + +pub fn bytes_fields_test() { + let bits = << + // field 3 + 0x1a, + 0x03, + 0x01, + 0x02, + 0x03, + // field 9 + 0x4a, + 0x04, + 0x0a, + 0x0b, + 0x0c, + 0x0d, + >> + let assert Ok(parsed) = parse(from: bits, using: bytes_fields_decoder()) + + assert parsed + == Parsed( + value: BytesFields(data: <<0x01, 0x02, 0x03>>, tag: << + 0x0a, + 0x0b, + 0x0c, + 0x0d, + >>), + rest: <<>>, + pos: 11, + ) +} + pub fn does_not_ignore_groups_test() { let path = "./test/ignores-groups.pb" let assert Ok(bits) = file.read_bits(from: path) -- tangled.sh