let raw_to_item () :
(raw_item, (item, [> Error.raw_to_item]) Result.t) Biocaml_transform.t =
let name = "sam_item_parser" in
let raw_queue = Dequeue.create () in
let raw_items_count = ref 0 in
let refseq_line, refseq_end = reference_sequence_aggregator () in
let header_finished = ref false in
let ref_dictionary = ref None in
let rec next stopped =
if Dequeue.is_empty raw_queue
then (if stopped then `end_of_stream else `not_ready)
else begin
incr raw_items_count;
begin match Dequeue.dequeue_exn raw_queue `front with
| `comment c when !header_finished ->
`output (Error (`comment_after_end_of_header (!raw_items_count, c)))
| `header c when !header_finished ->
`output (Error (`header_after_end_of_header (!raw_items_count, c)))
| `comment c -> `output (Ok (`comment c))
| `header ("HD", l) ->
if !raw_items_count <> 1
then `output (Error (`header_line_not_first !raw_items_count))
else `output (expand_header_line l)
| `header ("SQ", l) ->
begin match refseq_line l with
| Error e -> `output (Error e)
| Ok () -> next stopped
end
| `header _ as other -> `output (Ok other)
| `alignment a ->
if !header_finished then (
expand_alignment a !ref_dictionary
>>| (fun a -> `alignment a)
|> (fun x -> `output x)
) else begin
header_finished := true;
Dequeue.enqueue raw_queue `front (`alignment a);
begin match refseq_end () with
| Ok rd ->
ref_dictionary := Some rd;
`output (Ok (`reference_sequence_dictionary rd))
| Error e -> `output (Error e)
end
end
end
end
in
Biocaml_transform.make ~name ~feed:(Dequeue.enqueue raw_queue `back) ()
~next