open Stdint
open Misc
type b = {buffer : bytes; mutable offset: int}
let max_length = 1 lsl 31 - 1
let bool b =
let c = Bytes.get b.buffer b.offset in
let r =
if c = '\001' then true
else if c = '\000' then false
else failwith (Format.sprintf "character %C is not a boolean" c) in
b.offset <- b.offset + 1;
{r; depth=0}
let uint8 b =
let r = Uint8.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 1;
{r; depth=0}
let uint16 b =
let r = Uint16.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 2;
{r; depth=0}
let uint32 b =
let r = Uint32.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 4;
{r; depth=0}
let uint64 b =
let r = Uint64.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 8;
{r; depth=0}
let uint128 b =
let r = Uint128.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 16;
{r; depth=0}
let int8 b =
let r = Int8.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 1;
{r; depth=0}
let int16 b =
let r = Int16.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 2;
{r; depth=0}
let int32 b =
let r = Int32.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 4;
{r; depth=0}
let int64 b =
let r = Int64.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 8;
{r; depth=0}
let int128 b =
let r = Int128.of_bytes_little_endian b.buffer b.offset in
b.offset <- b.offset + 16;
{r; depth=0}
let option f b =
let bo = bool b in
if not bo.r then {r=None; depth=0}
else
let r = f b in
{r with r=Some r.r}
let unit (_ : b) = {r=(); depth=0}
let fixed f n b =
let rec aux b acc i =
if i = 0 then {acc with r = Array.of_list @@ List.rev acc.r}
else
let x = f b in
let depth = max acc.depth x.depth in
aux b {r=x.r :: acc.r; depth} (i-1) in
aux b {r=[]; depth=0} n
let variable length f b =
let n = length b in
let rec aux b acc i =
if i = 0 then {acc with r = List.rev acc.r}
else
let x = f b in
let depth = max acc.depth x.depth in
aux b {r=x.r :: acc.r; depth} (i-1) in
aux b {r=[]; depth=0} n
let is_utf8_string s =
let decoder = Uutf.decoder ~encoding:`UTF_8 (`String s) in
let rec aux decoder =
match Uutf.decode decoder with
| `Uchar _ -> aux decoder
| `End -> true
| `Malformed _ -> false
| `Await -> false in
aux decoder
let string length b =
let n = length b in
let r = Bytes.sub b.buffer b.offset n in
b.offset <- b.offset + n;
let s = Bytes.to_string r in
if is_utf8_string s then {r=s; depth=0} else failwith "non utf8 string"
let bytes length b =
let n = length b in
let r = Bytes.sub b.buffer b.offset n in
b.offset <- b.offset + n;
{r; depth=0}
let map length ser_k de_k de_v b =
let compare k1 k2 = Bytes.compare (ser_k k1).r (ser_k k2).r in
let r = variable length (fun b ->
let (v, k) = de_v b, de_k b in
{depth = max k.depth v.depth; r = (k.r, v.r)}) b in
{ r with
r = snd @@ List.fold_left (fun (last_k, acc) (k, v) ->
match last_k with
| Some last_k when compare last_k k >= 0 -> failwith "map not ordered"
| _ -> (Some k, Map.add ~compare k v acc)) (None, Map.empty) r.r }