mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-06 21:28:01 +00:00
136 lines
3.6 KiB
Text
136 lines
3.6 KiB
Text
module [ByteEncoder, sequence, u8, u16, bytes, empty, encode]
|
|
|
|
Endianness : [BE, LE]
|
|
|
|
ByteEncoder : [Signed8 I8, Unsigned8 U8, Signed16 Endianness I16, Unsigned16 Endianness U16, Sequence U64 (List ByteEncoder), Bytes (List U8)]
|
|
|
|
u8 : U8 -> ByteEncoder
|
|
u8 = \value -> Unsigned8(value)
|
|
|
|
empty : ByteEncoder
|
|
empty =
|
|
foo : List ByteEncoder
|
|
foo = []
|
|
|
|
Sequence(0, foo)
|
|
|
|
u16 : Endianness, U16 -> ByteEncoder
|
|
u16 = \endianness, value -> Unsigned16(endianness, value)
|
|
|
|
bytes : List U8 -> ByteEncoder
|
|
bytes = \bs -> Bytes(bs)
|
|
|
|
sequence : List ByteEncoder -> ByteEncoder
|
|
sequence = \encoders ->
|
|
Sequence(get_widths(encoders, 0), encoders)
|
|
|
|
get_width : ByteEncoder -> U64
|
|
get_width = \encoder ->
|
|
when encoder is
|
|
Signed8(_) -> 1
|
|
Unsigned8(_) -> 1
|
|
Signed16(_, _) -> 2
|
|
Unsigned16(_, _) -> 2
|
|
# Signed32 _ -> 4
|
|
# Unsigned32 _ -> 4
|
|
# Signed64 _ -> 8
|
|
# Unsigned64 _ -> 8
|
|
# Signed128 _ -> 16
|
|
# Unsigned128 _ -> 16
|
|
Sequence(w, _) -> w
|
|
Bytes(bs) -> List.len(bs)
|
|
|
|
get_widths : List ByteEncoder, U64 -> U64
|
|
get_widths = \encoders, initial ->
|
|
List.walk(encoders, initial, \accum, encoder -> accum + get_width(encoder))
|
|
|
|
encode : ByteEncoder -> List U8
|
|
encode = \encoder ->
|
|
output = List.repeat(0, get_width(encoder))
|
|
|
|
encode_help(encoder, 0, output)
|
|
|> .output
|
|
|
|
encode_help : ByteEncoder, U64, List U8 -> { output : List U8, offset : U64 }
|
|
encode_help = \encoder, offset, output ->
|
|
when encoder is
|
|
Unsigned8(value) ->
|
|
{
|
|
output: List.set(output, offset, value),
|
|
offset: offset + 1,
|
|
}
|
|
|
|
Signed8(value) ->
|
|
cast : U8
|
|
cast = Num.int_cast(value)
|
|
|
|
{
|
|
output: List.set(output, offset, cast),
|
|
offset: offset + 1,
|
|
}
|
|
|
|
Unsigned16(endianness, value) ->
|
|
a : U8
|
|
a = Num.int_cast(Num.shift_right_by(value, 8))
|
|
|
|
b : U8
|
|
b = Num.int_cast(value)
|
|
|
|
new_output =
|
|
when endianness is
|
|
BE ->
|
|
output
|
|
|> List.set((offset + 0), a)
|
|
|> List.set((offset + 1), b)
|
|
|
|
LE ->
|
|
output
|
|
|> List.set((offset + 0), b)
|
|
|> List.set((offset + 1), a)
|
|
|
|
{
|
|
output: new_output,
|
|
offset: offset + 2,
|
|
}
|
|
|
|
Signed16(endianness, value) ->
|
|
a : U8
|
|
a = Num.int_cast(Num.shift_right_by(value, 8))
|
|
|
|
b : U8
|
|
b = Num.int_cast(value)
|
|
|
|
new_output =
|
|
when endianness is
|
|
BE ->
|
|
output
|
|
|> List.set((offset + 0), a)
|
|
|> List.set((offset + 1), b)
|
|
|
|
LE ->
|
|
output
|
|
|> List.set((offset + 0), b)
|
|
|> List.set((offset + 1), a)
|
|
|
|
{
|
|
output: new_output,
|
|
offset: offset + 1,
|
|
}
|
|
|
|
Bytes(bs) ->
|
|
List.walk(
|
|
bs,
|
|
{ output, offset },
|
|
\accum, byte -> {
|
|
offset: accum.offset + 1,
|
|
output: List.set(accum.output, offset, byte),
|
|
},
|
|
)
|
|
|
|
Sequence(_, encoders) ->
|
|
List.walk(
|
|
encoders,
|
|
{ output, offset },
|
|
\accum, single ->
|
|
encode_help(single, accum.offset, accum.output),
|
|
)
|