From f1f46a0e521a700fc79bd38a44425d9eb40531d7 Mon Sep 17 00:00:00 2001 From: Gavin Morrow Date: Fri, 19 Sep 2025 21:29:15 -0400 Subject: [PATCH] Split into modules --- src/decoders.gleam | 40 +++++++++++++++++++++++ src/internal/util.gleam | 8 +++++ src/protobuf_decode_gleam.gleam | 47 ++------------------------- test/protobuf_decode_gleam_test.gleam | 6 ++-- 4 files changed, 54 insertions(+), 47 deletions(-) create mode 100644 src/decoders.gleam create mode 100644 src/internal/util.gleam diff --git a/src/decoders.gleam b/src/decoders.gleam new file mode 100644 index 0000000..35cf204 --- /dev/null +++ b/src/decoders.gleam @@ -0,0 +1,40 @@ +import gleam/bit_array +import gleam/dynamic/decode.{type Decoder} + +import internal/util +import protobuf_decode_gleam.{parse} + +pub fn decode_protobuf( + using decoder: fn() -> Decoder(t), + named name: String, + default default: t, +) -> Decoder(t) { + use bits <- decode.then(decode.bit_array) + + let value = parse(from: bits, using: decoder()) + case value { + Ok(value) -> decode.success(value) + Error(_) -> decode.failure(default, name) + } +} + +pub fn decode_uint() -> Decoder(Int) { + use bits <- decode.then(decode.bit_array) + util.bit_array_to_uint(bits) |> decode.success +} + +pub fn decode_fixed(size: Int) -> Decoder(Int) { + use bits <- decode.then(decode.bit_array) + let assert <> = bits + num |> decode.success +} + +pub fn decode_string() -> Decoder(String) { + use bits <- decode.then(decode.bit_array) + + let str = bit_array.to_string(bits) + case str { + Ok(str) -> decode.success(str) + Error(_) -> decode.failure("", "String") + } +} diff --git a/src/internal/util.gleam b/src/internal/util.gleam new file mode 100644 index 0000000..8d91e7c --- /dev/null +++ b/src/internal/util.gleam @@ -0,0 +1,8 @@ +import gleam/bit_array + +pub fn bit_array_to_uint(bits: BitArray) -> Int { + let size = bit_array.bit_size(bits) + // Interpert the entire bit array as an unsigned int + let assert <> = bits + n +} diff --git a/src/protobuf_decode_gleam.gleam b/src/protobuf_decode_gleam.gleam index f2454a2..f8b20a6 100644 --- a/src/protobuf_decode_gleam.gleam +++ b/src/protobuf_decode_gleam.gleam @@ -6,6 +6,7 @@ import gleam/list import gleam/option import gleam/result +import internal/util import internal/wire_type.{type WireType} pub fn parse( @@ -16,20 +17,6 @@ pub fn parse( decode.run(data, decoder) |> result.map_error(UnableToDecode) } -pub fn decode_protobuf( - using decoder: fn() -> Decoder(t), - named name: String, - default default: t, -) -> Decoder(t) { - use bits <- decode.then(decode.bit_array) - - let value = parse(from: bits, using: decoder()) - case value { - Ok(value) -> decode.success(value) - Error(_) -> decode.failure(default, name) - } -} - pub type DecodeError { UnknownWireType(Int) InvalidVarInt(leftover_bits: BitArray, acc: BitArray) @@ -83,7 +70,7 @@ fn wire_type_read_fn(ty: WireType) -> fn(BitArray) -> ValueResult { fn read_field(bits: BitArray) -> DecodeResult(Parsed(Field)) { use Parsed(value: tag, rest: bits) <- result.try(read_varint(bits)) - let tag = bit_array_to_uint(tag) + let tag = util.bit_array_to_uint(tag) let field_id = tag |> int.bitwise_shift_right(3) let wire_type = tag |> int.bitwise_and(0b111) @@ -137,7 +124,7 @@ fn read_len(bits: BitArray) -> ValueResult { // First, read the length of the value // It is encoded as a varint immediately after the tag use Parsed(value: len, rest: bits) <- result.try(read_varint(bits)) - let len = bit_array_to_uint(len) + let len = util.bit_array_to_uint(len) // Just decoded a uint, so should be safe assert len > 0 @@ -152,31 +139,3 @@ fn read_len(bits: BitArray) -> ValueResult { Ok(Parsed(value:, rest:)) } - -pub fn decode_uint() -> Decoder(Int) { - use bits <- decode.then(decode.bit_array) - bit_array_to_uint(bits) |> decode.success -} - -pub fn decode_fixed(size: Int) -> Decoder(Int) { - use bits <- decode.then(decode.bit_array) - let assert <> = bits - num |> decode.success -} - -pub fn decode_string() -> Decoder(String) { - use bits <- decode.then(decode.bit_array) - - let str = bit_array.to_string(bits) - case str { - Ok(str) -> decode.success(str) - Error(_) -> decode.failure("", "String") - } -} - -fn bit_array_to_uint(bits: BitArray) -> Int { - let size = bit_array.bit_size(bits) - // Interpert the entire bit array as an unsigned int - let assert <> = bits - n -} diff --git a/test/protobuf_decode_gleam_test.gleam b/test/protobuf_decode_gleam_test.gleam index b64e725..58ccbb1 100644 --- a/test/protobuf_decode_gleam_test.gleam +++ b/test/protobuf_decode_gleam_test.gleam @@ -1,11 +1,11 @@ import gleam/dynamic/decode.{type Decoder} import gleam/option import gleeunit -import protobuf_decode_gleam.{ - decode_fixed, decode_protobuf, decode_string, decode_uint, parse, -} import simplifile as file +import decoders.{decode_fixed, decode_protobuf, decode_string, decode_uint} +import protobuf_decode_gleam.{parse} + pub fn main() -> Nil { gleeunit.main() } -- 2.51.2