package SZXX

  1. Overview
  2. Docs

Source file feed.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
open! Base

(** Feeds can also be created manually without going through the convenience functions in this module *)
type t = unit -> [ `String of string | `Bigstring of Bigstringaf.t | `Eof ]

(** Create a [Feed.t] from a standard [Eio.Flow.source] *)
let of_flow ?(slice_size = 4096) (src : _ Eio.Flow.source) : t =
  let buf = Cstruct.create slice_size in
  fun () ->
    try
      let len = Eio.Flow.single_read src buf in
      `Bigstring (Bigstringaf.sub ~off:0 ~len buf.buffer)
    with
    | End_of_file -> `Eof

(** Same as [of_flow], but the resulting [Feed.t] does not advance the file cursor.
    In other words, even after processing, the flow will still appear to be "unread".
    Note: this function requires a flow that supports seeking, such as files. *)
let of_flow_seekable ?(slice_size = 4096) ?(offset = 0) (src : _ Eio.File.ro) : t =
  let buf = Cstruct.create slice_size in
  let pos = ref (Optint.Int63.of_int offset) in
  fun () ->
    try
      let len = Eio.File.pread src [ buf ] ~file_offset:!pos in
      (pos := Optint.Int63.(add !pos (of_int len)));
      `Bigstring (Bigstringaf.sub ~off:0 ~len buf.buffer)
    with
    | End_of_file -> `Eof

(** Return [None] to indicate End Of File *)
let of_string_dispenser f : t =
 fun () ->
  match f () with
  | Some s -> `String s
  | None -> `Eof

(** Return [None] to indicate End Of File *)
let of_bigstring_dispenser f : t =
 fun () ->
  match f () with
  | Some bs -> `Bigstring bs
  | None -> `Eof

(** Note: not ideal for extremely large strings. For that, use the other functions in this module. *)
let of_string ?(slice_size = 4096) s : t =
  let size = String.length s in
  (* By copying the string into a sequence of Bigstrings,
     we can reclaim memory as soon as the large string goes out of scope
     and the sequence starts being processed. *)
  let chunks =
    if size < slice_size
    then [ Bigstringaf.of_string s ~off:0 ~len:(String.length s) ]
    else (
      let n = size / slice_size in
      let rem = size - (slice_size * n) in
      let init = if rem = 0 then [] else [ Bigstringaf.of_string s ~off:(n * slice_size) ~len:rem ] in
      Array.init n ~f:Fn.id
      |> Array.fold_right ~init ~f:(fun i acc ->
           Bigstringaf.of_string s ~off:(i * slice_size) ~len:slice_size :: acc ) )
  in
  let acc = ref chunks in
  fun () ->
    match !acc with
    | [] -> `Eof
    | bs :: rest ->
      acc := rest;
      `Bigstring bs
OCaml

Innovation. Community. Security.