This commit is contained in:
parent
809d49d99c
commit
97bd0c70d6
2 changed files with 42 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
||||||
import gleam/bit_array
|
import gleam/bit_array
|
||||||
|
import gleam/list.{reverse}
|
||||||
import gleam/result.{try}
|
import gleam/result.{try}
|
||||||
import ieee_float.{
|
import ieee_float.{
|
||||||
type IEEEFloat, from_bytes_16_be, from_bytes_32_be, from_bytes_64_be,
|
type IEEEFloat, from_bytes_16_be, from_bytes_32_be, from_bytes_64_be,
|
||||||
|
@ -10,6 +11,7 @@ pub type DecodedValue {
|
||||||
Boolean(value: Bool)
|
Boolean(value: Bool)
|
||||||
Bytes(value: BitArray)
|
Bytes(value: BitArray)
|
||||||
String(value: String)
|
String(value: String)
|
||||||
|
Array(List(DecodedValue))
|
||||||
Null
|
Null
|
||||||
Undefined
|
Undefined
|
||||||
}
|
}
|
||||||
|
@ -42,6 +44,9 @@ pub fn decode(bits: BitArray) -> DecodeResult {
|
||||||
<<3:3, rest:bits>> ->
|
<<3:3, rest:bits>> ->
|
||||||
decode_string(rest)
|
decode_string(rest)
|
||||||
|> map_decoded(String)
|
|> map_decoded(String)
|
||||||
|
<<4:3, rest:bits>> ->
|
||||||
|
decode_array(rest)
|
||||||
|
|> map_decoded(Array)
|
||||||
<<7:3, x:5, rest:bits>> if x < 25 -> decode_simple(<<x:5, rest:bits>>)
|
<<7:3, x:5, rest:bits>> if x < 25 -> decode_simple(<<x:5, rest:bits>>)
|
||||||
<<7:3, x:5, rest:bits>> if x >= 25 ->
|
<<7:3, x:5, rest:bits>> if x >= 25 ->
|
||||||
decode_float(<<x:5, rest:bits>>)
|
decode_float(<<x:5, rest:bits>>)
|
||||||
|
@ -83,6 +88,11 @@ fn decode_string(bits: BitArray) -> DecoderResult(String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_array(bits: BitArray) -> DecoderResult(List(DecodedValue)) {
|
||||||
|
use #(length, rest) <- try(decode_int(bits))
|
||||||
|
decode_next_n([], rest, length)
|
||||||
|
}
|
||||||
|
|
||||||
fn decode_float(bits: BitArray) -> DecoderResult(IEEEFloat) {
|
fn decode_float(bits: BitArray) -> DecoderResult(IEEEFloat) {
|
||||||
case bits {
|
case bits {
|
||||||
<<25:5, float16:bytes-size(2), rest:bits>> ->
|
<<25:5, float16:bytes-size(2), rest:bits>> ->
|
||||||
|
@ -105,6 +115,22 @@ fn decode_simple(bits: BitArray) -> DecodeResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_next_n(
|
||||||
|
retrieved: List(DecodedValue),
|
||||||
|
rest: BitArray,
|
||||||
|
n: Int,
|
||||||
|
) -> DecoderResult(List(DecodedValue)) {
|
||||||
|
// Due to how Gleam handles lists, we build it in reverse
|
||||||
|
// and then reverse it at the end before returning
|
||||||
|
case n {
|
||||||
|
0 -> Ok(#(reverse(retrieved), rest))
|
||||||
|
n -> {
|
||||||
|
use #(next, rest) <- try(decode(rest))
|
||||||
|
decode_next_n([next, ..retrieved], rest, n - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn map_decoded(
|
fn map_decoded(
|
||||||
result: DecoderResult(t),
|
result: DecoderResult(t),
|
||||||
map_fn: fn(t) -> DecodedValue,
|
map_fn: fn(t) -> DecodedValue,
|
||||||
|
|
|
@ -3,8 +3,8 @@ import gleeunit
|
||||||
import gleeunit/should
|
import gleeunit/should
|
||||||
import ieee_float.{finite, nan, positive_infinity}
|
import ieee_float.{finite, nan, positive_infinity}
|
||||||
import kmer.{
|
import kmer.{
|
||||||
type DecodeResult, type DecodedValue, Boolean, Bytes, Float, Integer, Null,
|
type DecodeResult, type DecodedValue, Array, Boolean, Bytes, Float, Integer,
|
||||||
String, Undefined,
|
Null, String, Undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
@ -122,6 +122,20 @@ pub fn decode_string_test() {
|
||||||
|> table_fn(table_test_decode)
|
|> table_fn(table_test_decode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode_list_test() {
|
||||||
|
[
|
||||||
|
#(
|
||||||
|
<<4:3, 5:5, 1, 2, 3, 4, 5>>,
|
||||||
|
Array([Integer(1), Integer(2), Integer(3), Integer(4), Integer(5)]),
|
||||||
|
),
|
||||||
|
#(
|
||||||
|
<<4:3, 24:5, 3:8, 3:3, 11:5, "Hello world", 1:3, 24:5, 123:8, 3>>,
|
||||||
|
Array([String("Hello world"), Integer(-124), Integer(3)]),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|> table_fn(table_test_decode)
|
||||||
|
}
|
||||||
|
|
||||||
fn table_fn(tests: List(#(a, b)), test_fn: fn(a, b) -> Nil) {
|
fn table_fn(tests: List(#(a, b)), test_fn: fn(a, b) -> Nil) {
|
||||||
list.map(tests, fn(t) {
|
list.map(tests, fn(t) {
|
||||||
let #(test_case, expected) = t
|
let #(test_case, expected) = t
|
||||||
|
|
Loading…
Reference in a new issue