let parse_cigar ?(pos=0) ?len buf =
    let len =
      match len with Some s -> s | None -> String.length buf in
    begin match len mod 4 with
    | 0 -> return (len / 4)
    | n -> fail (`wrong_cigar_length len)
    end
    >>= fun n_cigar_op ->
    begin
      try
        return (Array.init n_cigar_op (fun i ->
          let open Int64 in
          let int64 =
            let int8 pos =
              Binary_packing.unpack_unsigned_8 ~buf ~pos |! Int64.of_int in
            int8 Int.(pos + i * 4)
            + shift_left (int8 Int.(pos + i * 4 + 1)) 8
            + shift_left (int8 Int.(pos + i * 4 + 2)) 16
            + shift_left (int8 Int.(pos + i * 4 + 3)) 24
          in
          let op_len = shift_right int64 4 |! Int64.to_int_exn in
          let op =
            match bit_and int64 0x0fL with
            | 0L -> `M op_len
            | 1L -> `I op_len
            | 2L -> `D op_len
            | 3L -> `N op_len
            | 4L -> `S op_len
            | 5L -> `H op_len
            | 6L -> `P op_len
            | 7L -> `Eq op_len
            | 8L -> `X op_len
            | any -> failwithf "OP:%Ld" any () in
          op))
      with
      | e ->
        fail (`wrong_cigar
                 String.(sub buf pos (pos + n_cigar_op * 4)))
    end