From 2a20ca270ac76b8d4c7b2b760543ea0135c5619d Mon Sep 17 00:00:00 2001 From: Gavin Morrow Date: Sun, 28 Sep 2025 21:12:49 -0400 Subject: [PATCH] Clean up naming and add documentation --- src/decoders.gleam | 4 +-- src/protobuf_decode_gleam.gleam | 44 ++++++++++++++++----------- test/protobuf_decode_gleam_test.gleam | 6 ++-- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/decoders.gleam b/src/decoders.gleam index de3b533..24cf3c6 100644 --- a/src/decoders.gleam +++ b/src/decoders.gleam @@ -7,7 +7,7 @@ import gleam/result import internal/util import protobuf_decode_gleam.{ - type BytePos, type DecodeResult, type ValueParser, Parsed, parse, read_varint, + type BytePos, type DecodeResult, type ValueParser, Parsed, parse, parse_varint, } /// Decode a repeated field that may be either packed or expanded. @@ -95,7 +95,7 @@ pub fn protobuf( pub fn uint() -> Decoder(Int) { use bits <- decode.then(single_or_raw(decode.bit_array)) - use bits <- decode.then(case read_varint(bits, 0) { + use bits <- decode.then(case parse_varint(bits, 0) { Ok(Parsed(value:, rest: <<>>, pos: _)) -> decode.success(value) _ -> decode.failure(<<>>, "uint") }) diff --git a/src/protobuf_decode_gleam.gleam b/src/protobuf_decode_gleam.gleam index 8313927..d2e4a5c 100644 --- a/src/protobuf_decode_gleam.gleam +++ b/src/protobuf_decode_gleam.gleam @@ -93,9 +93,9 @@ type Field { Field(key: Dynamic, value: Dynamic) } -fn wire_type_consume_fn(ty: WireType) -> ValueParser { +fn wire_type_read_fn(ty: WireType) -> ValueParser { case ty { - wire_type.VarInt -> consume_varint + wire_type.VarInt -> read_varint wire_type.I64 -> read_fixed(64) wire_type.Len -> read_len wire_type.I32 -> read_fixed(32) @@ -103,7 +103,7 @@ fn wire_type_consume_fn(ty: WireType) -> ValueParser { } fn read_field(bits: BitArray, tag_pos: BytePos) -> DecodeResult(Parsed(Field)) { - use Parsed(value: tag, rest: bits, pos:) <- result.try(read_varint( + use Parsed(value: tag, rest: bits, pos:) <- result.try(parse_varint( bits, tag_pos, )) @@ -124,9 +124,9 @@ fn read_field(bits: BitArray, tag_pos: BytePos) -> DecodeResult(Parsed(Field)) { UnknownWireType(wire_type, pos: tag_pos), )) - let consume = wire_type_consume_fn(wire_type) + let read = wire_type_read_fn(wire_type) use value: Parsed(Dynamic) <- result.try( - consume(bits, pos) |> result.map(parsed_map(_, dynamic.bit_array)), + read(bits, pos) |> result.map(parsed_map(_, dynamic.bit_array)), ) let field = @@ -141,15 +141,16 @@ pub type ValueResult = pub type ValueParser = fn(BitArray, BytePos) -> ValueResult -pub fn consume_varint(bits: BitArray, pos: BytePos) -> ValueResult { - consume_varint_acc(bits, <<>>, pos) +/// Reads the bits from a varint and returns *all* of them. They cannot be +/// parsed as a uint. +/// +/// Specifically, the continuation bits are included, so the value's bit size +/// will be a multiple of 8. +pub fn read_varint(bits: BitArray, pos: BytePos) -> ValueResult { + read_varint_acc(bits, <<>>, pos) } -fn consume_varint_acc( - bits: BitArray, - acc: BitArray, - pos: BytePos, -) -> ValueResult { +fn read_varint_acc(bits: BitArray, acc: BitArray, pos: BytePos) -> ValueResult { case bits { <<0:size(1), n:bits-size(7), rest:bytes>> -> { let bit = <<0:size(1), n:bits>> @@ -158,24 +159,31 @@ fn consume_varint_acc( } <<1:size(1), n:bits-size(7), rest:bytes>> -> { let bit = <<1:size(1), n:bits>> - consume_varint_acc(rest, bit_array.concat([acc, bit]), pos + 1) + read_varint_acc(rest, bit_array.concat([acc, bit]), pos + 1) } bits -> Error(InvalidVarInt(leftover_bits: bits, acc:, pos:)) } } -pub fn read_varint(bits: BitArray, pos: BytePos) -> ValueResult { - read_varint_acc(bits, <<>>, pos) +/// Reads the bits from a varint and parses them a BitArray. The returned bits +/// can be parsed as a uint. +/// +/// For a decoder that does this, use `decoders.uint()`. +/// +/// The continuation bits are not included, so the value's bit size will be a +/// multiple of 7. +pub fn parse_varint(bits: BitArray, pos: BytePos) -> ValueResult { + parse_varint_acc(bits, <<>>, pos) } -fn read_varint_acc(bits: BitArray, acc: BitArray, pos: BytePos) -> ValueResult { +fn parse_varint_acc(bits: BitArray, acc: BitArray, pos: BytePos) -> ValueResult { case bits { <<0:size(1), n:bits-size(7), rest:bytes>> -> { let acc = bit_array.concat([n, acc]) Ok(Parsed(value: acc, rest:, pos: pos + 1)) } <<1:size(1), n:bits-size(7), rest:bytes>> -> - read_varint_acc(rest, bit_array.concat([n, acc]), pos + 1) + parse_varint_acc(rest, bit_array.concat([n, acc]), pos + 1) bits -> { Error(InvalidVarInt(leftover_bits: bits, acc:, pos:)) } @@ -197,7 +205,7 @@ pub fn read_fixed(size: Int) -> ValueParser { fn read_len(bits: BitArray, len_pos: BytePos) -> ValueResult { // First, read the length of the value // It is encoded as a varint immediately after the tag - use Parsed(value: len, rest: bits, pos:) <- result.try(read_varint( + use Parsed(value: len, rest: bits, pos:) <- result.try(parse_varint( bits, len_pos, )) diff --git a/test/protobuf_decode_gleam_test.gleam b/test/protobuf_decode_gleam_test.gleam index c7e7bb2..9eef55e 100644 --- a/test/protobuf_decode_gleam_test.gleam +++ b/test/protobuf_decode_gleam_test.gleam @@ -4,7 +4,7 @@ import gleeunit import simplifile as file import decoders -import protobuf_decode_gleam.{Parsed, consume_varint, parse} +import protobuf_decode_gleam.{Parsed, read_varint, parse} pub fn main() -> Nil { gleeunit.main() @@ -197,11 +197,11 @@ type PackedFields { fn packed_fields_decoder() -> Decoder(PackedFields) { use packed <- decode.field( 3, - decoders.multiple(of: decoders.uint(), using: consume_varint), + decoders.multiple(of: decoders.uint(), using: read_varint), ) use expanded <- decode.field( 4, - decoders.multiple(of: decoders.uint(), using: consume_varint), + decoders.multiple(of: decoders.uint(), using: read_varint), ) PackedFields(packed:, expanded:) |> decode.success } -- 2.51.2