diff --git a/src/protobin.gleam b/src/protobin.gleam index 2abb3dd..30a46dc 100644 --- a/src/protobin.gleam +++ b/src/protobin.gleam @@ -379,6 +379,15 @@ pub fn decode_uint() -> Decoder(Int) { bits |> util.bit_array_to_uint |> decode.success } +pub fn decode_sint() -> Decoder(Int) { + use n <- decode.then(decode_uint()) + case int.is_even(n) { + True -> n / 2 + False -> int.negate({ n + 1 } / 2) + } + |> decode.success +} + pub fn decode_fixed(size: Int) -> Decoder(Int) { use bits <- decode.then(single_or_raw_bit_array()) case bits { diff --git a/test/protobin_test.gleam b/test/protobin_test.gleam index 71dabfe..fc1541d 100644 --- a/test/protobin_test.gleam +++ b/test/protobin_test.gleam @@ -112,6 +112,29 @@ pub fn two_ints_test() { assert data == Test(id: 150, age: 80_150) } +fn two_sints_decoder() -> Decoder(TwoInts) { + use id <- decode.field(1, protobin.decode_sint()) + use age <- decode.field(2, protobin.decode_sint()) + + Test(id:, age:) |> decode.success +} + +pub fn two_sints_test() { + let bits = << + // field 1 + 0x08, + 0x01, + // field 2 + 0x10, + 0x96, + 0x01, + >> + + let assert Ok(Parsed(value: data, rest: <<>>, pos: 5)) = + parse(from: bits, using: two_sints_decoder()) + assert data == Test(id: -1, age: 75) +} + pub type FeedHeader { FeedHeader(gtfs_realtime_version: String, timestamp: Int, nyct: NyctHeader) }