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)