let parse_optional_content raw =
let open Result.Monad_infix in
let error e = Error (`wrong_optional (raw, e)) in
let char tag typ raw =
if String.length raw <> 1 then error (`not_a_char raw)
else Ok (tag, typ, `char raw.[0]) in
let int tag typ raw =
try let i = Int.of_string raw in Ok (tag, typ, `int i)
with e -> error (`not_an_int raw) in
let float tag typ raw =
try let i = Float.of_string raw in Ok (tag, typ, `float i)
with e -> error (`not_a_float raw) in
let parse_cCsSiIf tag typ raw =
begin match typ with
| 'i' | 's' | 'I' | 'S' -> int tag typ raw
| 'A' | 'c' | 'C' -> char tag typ raw
| 'f' -> float tag typ raw
| _ -> error (`unknown_type typ)
end in
Result.List.mapi raw (fun _ (tag, typ, raw_v) ->
begin match typ with
| 'Z' -> Ok (tag, typ, `string raw_v)
| 'H' -> Ok (tag, typ, `string raw_v)
| 'B' ->
begin match String.split ~on:',' raw_v with
| [] -> error (`wrong_array (`wrong_type raw_v))
| f :: _ when String.length f <> 1 ->
error (`wrong_array (`wrong_type raw_v))
| typs :: l ->
let array = Array.create List.(length l) (`string "no") in
let rec loop i = function
| [] -> Ok array
| h :: t ->
begin match parse_cCsSiIf "" typs.[0] h with
| Ok (_, _, v) -> array.(i) <- v; loop (i + 1) t
| Error (`wrong_optional (_, e)) -> error (`wrong_array e)
end
in
loop 0 l
>>= fun a ->
Ok (tag, typ, `array (typs.[0], a))
end
| c -> parse_cCsSiIf tag typ raw_v
end)