let unit_to_random_char_seq_raw_item specification =
let open Result in
let tags =
get_tags specification
|> Option.value ~default:Tags.char_sequence_default in
begin match tags.Tags.sequence with
| `char_sequence intags ->
let has_comments =
Tags.sharp_comments tags || Tags.semicolon_comments tags in
let impose_sequence_alphabet = Tags.impose_sequence_alphabet tags in
let only_header_comment = Tags.only_header_comment tags in
let max_items_per_line = Tags.max_items_per_line tags in
let non_sequence_probability =
List.find_map specification
(function `non_sequence_probability p -> Some p | _ -> None)
|> Option.value ~default:0.2 in
let random_letter: 'a -> Char.t =
match impose_sequence_alphabet with
| Some f ->
(fun _ ->
let rec pick n =
if (f n) then n else pick (Random.int 127 |> Char.of_int_exn) in
pick (Random.int 127 |> Char.of_int_exn))
| None -> (fun _ -> Random.int 26 + 65 |> Char.of_int_exn) in
let header_or_comment =
let first_time = ref true in
fun id ->
if !first_time
then (
begin match Random.int 3 with
| 0 when has_comments -> `comment "Some random comment"
| _ ->
first_time := false;
ksprintf (fun s -> `header s) "Sequence %d" id
end
) else (
begin match Random.int 5 with
| 0 when has_comments && not only_header_comment ->
`comment "Some random comment"
| _ -> ksprintf (fun s -> `header s) "Sequence %d" id
end
) in
let next_raw_item =
let sequence_allowed = ref false in
let seq_num = ref 0 in
fun () ->
if !sequence_allowed then
begin match Random.float 1. with
| f when f <= non_sequence_probability ->
incr seq_num; header_or_comment !seq_num
| _ ->
let items_per_line = 1 + Random.int max_items_per_line in
`partial_sequence (String.init items_per_line random_letter)
end
else
begin match header_or_comment !seq_num with
| `header _ as h -> sequence_allowed := true; h
| other -> other
end
in
let todo = ref 0 in
return (Biocaml_transform.make ()
~next:(fun stopped ->
match !todo, stopped with
| 0, true -> `end_of_stream
| 0, false -> `not_ready
| n, _ when n < 0 -> assert false
| n, _ ->
decr todo;
`output (next_raw_item ()))
~feed:(fun () -> incr todo))
| `int_sequence ->
fail (`inconsistent_tags `int_sequence)
end