···11-import gleam/bit_array
22-import gleam/dynamic
33-import gleam/dynamic/decode.{type Decoder}
44-import gleam/int
55-import gleam/list
66-import gleam/result
77-88-import protobin.{
99- type BytePos, type DecodeResult, type ValueParser, Parsed, parse, parse_varint,
1010-}
1111-import protobin/internal/util
1212-1313-/// Decode a repeated field that may be either packed or expanded.
1414-///
1515-/// If it is impossible for a field to be packed (ie because it is encoded as
1616-/// a `LEN`) and therefore there is no `ValueParser` for it, then use the
1717-/// stdlib's `decode.list()` instead.
1818-pub fn multiple(
1919- of decoder: Decoder(t),
2020- using parser: ValueParser,
2121-) -> Decoder(List(t)) {
2222- use values <- decode.then(packed_values(of: decoder, using: parser))
2323- values |> decode.success
2424-}
2525-2626-fn packed_values(
2727- of decoder: Decoder(t),
2828- using parser: ValueParser,
2929-) -> Decoder(List(t)) {
3030- use bits <- decode.then(decode.list(of: decode.bit_array))
3131- let bits =
3232- list.fold(bits, <<>>, fn(acc, elem) { bit_array.concat([acc, elem]) })
3333-3434- let values = {
3535- use values <- result.try(unpack_bits(bits, [], at: 0, using: parser))
3636- values
3737- |> list.map(dynamic.bit_array)
3838- |> list.try_map(fn(value) { decode.run(value, decoder) })
3939- |> result.map_error(protobin.UnableToDecode)
4040- }
4141-4242- case values {
4343- Ok(values) -> decode.success(values)
4444- Error(_) -> decode.failure([], "Packed values")
4545- }
4646-}
4747-4848-fn unpack_bits(
4949- bits: BitArray,
5050- acc: List(BitArray),
5151- at pos: BytePos,
5252- using parser: ValueParser,
5353-) -> DecodeResult(List(BitArray)) {
5454- case bits {
5555- <<>> -> acc |> list.reverse |> Ok
5656- bits -> {
5757- use Parsed(value:, rest:, pos:) <- result.try(parser(bits, pos))
5858- unpack_bits(rest, [value, ..acc], at: pos, using: parser)
5959- }
6060- }
6161-}
6262-6363-/// Expects a single value from a list. Panics if the list is empty.
6464-fn single(of decoder: Decoder(t)) -> Decoder(t) {
6565- use values <- decode.then(decode.list(of: decoder))
6666-6767- // I choose to use assert instead of `decode.failure` because the decode api
6868- // requires passing a name and default value, which is clunky and would've
6969- // added two parameters to this function.
7070- // The only times this could fail are programmer error on my part or using
7171- // this decoder on data not produced in a compatible way with this library.
7272- let assert Ok(value) = list.last(values)
7373- value |> decode.success
7474-}
7575-7676-// Allows the decoders to be used for either single or repeated fields
7777-fn single_or_raw(decoder: Decoder(t)) -> Decoder(t) {
7878- decode.one_of(decoder, or: [single(of: decoder)])
7979-}
8080-8181-pub fn protobuf(
8282- // Passed as a function so recursive decoders are easier
8383- using decoder: fn() -> Decoder(t),
8484- named name: String,
8585- default default: t,
8686-) -> Decoder(t) {
8787- use bits <- decode.then(single_or_raw(decode.bit_array))
8888-8989- let value = parse(from: bits, using: decoder())
9090- case value {
9191- Ok(Parsed(value:, ..)) -> decode.success(value)
9292- Error(_) -> decode.failure(default, name)
9393- }
9494-}
9595-9696-pub fn uint() -> Decoder(Int) {
9797- use bits <- decode.then(single_or_raw(decode.bit_array))
9898- use bits <- decode.then(case parse_varint(bits, 0) {
9999- Ok(Parsed(value:, rest: <<>>, pos: _)) -> decode.success(value)
100100- _ -> decode.failure(<<>>, "uint")
101101- })
102102- bits |> util.bit_array_to_uint |> decode.success
103103-}
104104-105105-pub fn fixed(size: Int) -> Decoder(Int) {
106106- use bits <- decode.then(single_or_raw(decode.bit_array))
107107- case bits {
108108- <<num:unsigned-little-size(size)>> -> decode.success(num)
109109- _ -> decode.failure(0, "Fixed(" <> int.to_string(size) <> ")")
110110- }
111111-}
112112-113113-pub fn string() -> Decoder(String) {
114114- use bits <- decode.then(single_or_raw(decode.bit_array))
115115-116116- let str = bit_array.to_string(bits)
117117- case str {
118118- Ok(str) -> decode.success(str)
119119- Error(_) -> decode.failure("", "String")
120120- }
121121-}
+110
src/protobin.gleam
···226226227227 Ok(Parsed(value:, rest:, pos: pos + len))
228228}
229229+230230+/// Decode a repeated field that may be either packed or expanded.
231231+///
232232+/// If it is impossible for a field to be packed (ie because it is encoded as
233233+/// a `LEN`) and therefore there is no `ValueParser` for it, then use the
234234+/// stdlib's `decode.list()` instead.
235235+pub fn decode_multiple(
236236+ of decoder: Decoder(t),
237237+ using parser: ValueParser,
238238+) -> Decoder(List(t)) {
239239+ use values <- decode.then(packed_values(of: decoder, using: parser))
240240+ values |> decode.success
241241+}
242242+243243+fn packed_values(
244244+ of decoder: Decoder(t),
245245+ using parser: ValueParser,
246246+) -> Decoder(List(t)) {
247247+ use bits <- decode.then(decode.list(of: decode.bit_array))
248248+ let bits =
249249+ list.fold(bits, <<>>, fn(acc, elem) { bit_array.concat([acc, elem]) })
250250+251251+ let values = {
252252+ use values <- result.try(unpack_bits(bits, [], at: 0, using: parser))
253253+ values
254254+ |> list.map(dynamic.bit_array)
255255+ |> list.try_map(fn(value) { decode.run(value, decoder) })
256256+ |> result.map_error(UnableToDecode)
257257+ }
258258+259259+ case values {
260260+ Ok(values) -> decode.success(values)
261261+ Error(_) -> decode.failure([], "Packed values")
262262+ }
263263+}
264264+265265+fn unpack_bits(
266266+ bits: BitArray,
267267+ acc: List(BitArray),
268268+ at pos: BytePos,
269269+ using parser: ValueParser,
270270+) -> DecodeResult(List(BitArray)) {
271271+ case bits {
272272+ <<>> -> acc |> list.reverse |> Ok
273273+ bits -> {
274274+ use Parsed(value:, rest:, pos:) <- result.try(parser(bits, pos))
275275+ unpack_bits(rest, [value, ..acc], at: pos, using: parser)
276276+ }
277277+ }
278278+}
279279+280280+/// Expects a single value from a list. Panics if the list is empty.
281281+fn single(of decoder: Decoder(t)) -> Decoder(t) {
282282+ use values <- decode.then(decode.list(of: decoder))
283283+284284+ // I choose to use assert instead of `decode.failure` because the decode api
285285+ // requires passing a name and default value, which is clunky and would've
286286+ // added two parameters to this function.
287287+ // The only times this could fail are programmer error on my part or using
288288+ // this decoder on data not produced in a compatible way with this library.
289289+ let assert Ok(value) = list.last(values)
290290+ value |> decode.success
291291+}
292292+293293+// Allows the decoders to be used for either single or repeated fields
294294+fn single_or_raw(decoder: Decoder(t)) -> Decoder(t) {
295295+ decode.one_of(decoder, or: [single(of: decoder)])
296296+}
297297+298298+pub fn decode_protobuf(
299299+ // Passed as a function so recursive decoders are easier
300300+ using decoder: fn() -> Decoder(t),
301301+ named name: String,
302302+ default default: t,
303303+) -> Decoder(t) {
304304+ use bits <- decode.then(single_or_raw(decode.bit_array))
305305+306306+ let value = parse(from: bits, using: decoder())
307307+ case value {
308308+ Ok(Parsed(value:, ..)) -> decode.success(value)
309309+ Error(_) -> decode.failure(default, name)
310310+ }
311311+}
312312+313313+pub fn decode_uint() -> Decoder(Int) {
314314+ use bits <- decode.then(single_or_raw(decode.bit_array))
315315+ use bits <- decode.then(case parse_varint(bits, 0) {
316316+ Ok(Parsed(value:, rest: <<>>, pos: _)) -> decode.success(value)
317317+ _ -> decode.failure(<<>>, "uint")
318318+ })
319319+ bits |> util.bit_array_to_uint |> decode.success
320320+}
321321+322322+pub fn decode_fixed(size: Int) -> Decoder(Int) {
323323+ use bits <- decode.then(single_or_raw(decode.bit_array))
324324+ case bits {
325325+ <<num:unsigned-little-size(size)>> -> decode.success(num)
326326+ _ -> decode.failure(0, "Fixed(" <> int.to_string(size) <> ")")
327327+ }
328328+}
329329+330330+pub fn decode_string() -> Decoder(String) {
331331+ use bits <- decode.then(single_or_raw(decode.bit_array))
332332+333333+ let str = bit_array.to_string(bits)
334334+ case str {
335335+ Ok(str) -> decode.success(str)
336336+ Error(_) -> decode.failure("", "String")
337337+ }
338338+}
+21-19
test/protobin_test.gleam
···33import gleeunit
44import simplifile as file
5566-import decoders
76import protobin.{Parsed, parse, read_fixed, read_varint}
8798pub fn main() -> Nil {
···24232524fn person_decoder() -> Decoder(Person) {
2625 let person_inner_decoder =
2727- decoders.protobuf(
2626+ protobin.decode_protobuf(
2827 using: person_decoder,
2928 named: "Person",
3029 default: default_person,
3130 )
32313333- use id <- decode.field(3, decoders.fixed(64))
3434- use age <- decode.field(1, decoders.uint())
3535- use score <- decode.field(2, decoders.uint())
3232+ use id <- decode.field(3, protobin.decode_fixed(64))
3333+ use age <- decode.field(1, protobin.decode_uint())
3434+ use score <- decode.field(2, protobin.decode_uint())
3635 use person <- decode.optional_field(
3736 4,
3837 option.None,
3938 decode.optional(person_inner_decoder),
4039 )
4141- use day <- decode.field(5, decoders.fixed(32))
4040+ use day <- decode.field(5, protobin.decode_fixed(32))
42414342 Person(id:, age:, score:, self: person, day:) |> decode.success
4443}
···7170}
72717372fn two_ints_decoder() -> Decoder(TwoInts) {
7474- use id <- decode.field(1, decoders.uint())
7575- use age <- decode.field(2, decoders.uint())
7373+ use id <- decode.field(1, protobin.decode_uint())
7474+ use age <- decode.field(2, protobin.decode_uint())
76757776 Test(id:, age:) |> decode.success
7877}
···121120)
122121123122fn feed_header_decoder() -> Decoder(FeedHeader) {
124124- use gtfs_realtime_version <- decode.field(1, decoders.string())
125125- use timestamp <- decode.field(3, decoders.fixed(64))
123123+ use gtfs_realtime_version <- decode.field(1, protobin.decode_string())
124124+ use timestamp <- decode.field(3, protobin.decode_fixed(64))
126125 use nyct <- decode.field(
127126 1001,
128128- decoders.protobuf(
127127+ protobin.decode_protobuf(
129128 using: nyct_header_decoder,
130129 named: "NyctHeader",
131130 default: nyct_header_default,
···135134}
136135137136fn nyct_header_decoder() -> Decoder(NyctHeader) {
138138- use version <- decode.field(1, decoders.string())
137137+ use version <- decode.field(1, protobin.decode_string())
139138140139 use trip_replacement_periods <- decode.field(
141140 2,
142142- decode.list(of: decoders.protobuf(
141141+ decode.list(of: protobin.decode_protobuf(
143142 using: trip_replacement_period_decoder,
144143 named: "TripReplacementPeriod",
145144 default: trip_replacement_period_default,
···150149}
151150152151fn trip_replacement_period_decoder() -> Decoder(TripReplacementPeriod) {
153153- use route_id <- decode.field(1, decoders.string())
152152+ use route_id <- decode.field(1, protobin.decode_string())
154153 use replacement_period <- decode.field(
155154 2,
156156- decoders.protobuf(
155155+ protobin.decode_protobuf(
157156 using: trip_replacement_period_time_range_decoder,
158157 named: "TripReplacePeriod.TimeRange",
159158 default: 0,
···163162}
164163165164fn trip_replacement_period_time_range_decoder() -> Decoder(Int) {
166166- use time <- decode.field(2, decoders.fixed(64))
165165+ use time <- decode.field(2, protobin.decode_fixed(64))
167166 time |> decode.success
168167}
169168···201200fn packed_fields_decoder() -> Decoder(PackedFields) {
202201 use packed <- decode.field(
203202 3,
204204- decoders.multiple(of: decoders.uint(), using: read_varint),
203203+ protobin.decode_multiple(of: protobin.decode_uint(), using: read_varint),
205204 )
206205 use expanded <- decode.field(
207206 4,
208208- decoders.multiple(of: decoders.uint(), using: read_varint),
207207+ protobin.decode_multiple(of: protobin.decode_uint(), using: read_varint),
209208 )
210209 use mixed_packed_and_expanded <- decode.field(
211210 11,
212212- decoders.multiple(of: decoders.fixed(32), using: read_fixed(32)),
211211+ protobin.decode_multiple(
212212+ of: protobin.decode_fixed(32),
213213+ using: read_fixed(32),
214214+ ),
213215 )
214216 PackedFields(packed:, expanded:, mixed_packed_and_expanded:) |> decode.success
215217}