mirror of
https://github.com/c-cube/nanoev.git
synced 2025-12-05 19:00:35 -05:00
152 lines
3.5 KiB
OCaml
152 lines
3.5 KiB
OCaml
open Common_
|
|
|
|
class type t = object
|
|
method input : bytes -> int -> int -> int
|
|
(** Read into the slice. Returns [0] only if the stream is closed. *)
|
|
|
|
method close : unit -> unit
|
|
(** Close the input. Must be idempotent. *)
|
|
end
|
|
|
|
let create ?(close = ignore) ~input () : t =
|
|
object
|
|
method close = close
|
|
method input = input
|
|
end
|
|
|
|
let empty : t =
|
|
object
|
|
method close () = ()
|
|
method input _ _ _ = 0
|
|
end
|
|
|
|
let of_bytes ?(off = 0) ?len (b : bytes) : t =
|
|
(* i: current position in [b] *)
|
|
let i = ref off in
|
|
|
|
let len =
|
|
match len with
|
|
| Some n ->
|
|
if n > Bytes.length b - off then invalid_arg "Iostream.In.of_bytes";
|
|
n
|
|
| None -> Bytes.length b - off
|
|
in
|
|
let end_ = off + len in
|
|
|
|
object
|
|
method input b_out i_out len_out =
|
|
let n = min (end_ - !i) len_out in
|
|
Bytes.blit b !i b_out i_out n;
|
|
i := !i + n;
|
|
n
|
|
|
|
method close () = i := end_
|
|
end
|
|
|
|
let of_string ?off ?len s : t = of_bytes ?off ?len (Bytes.unsafe_of_string s)
|
|
|
|
(** Read into the given slice.
|
|
@return the number of bytes read, [0] means end of input. *)
|
|
let[@inline] input (self : #t) buf i len = self#input buf i len
|
|
|
|
(** Close the channel. *)
|
|
let[@inline] close self : unit = self#close ()
|
|
|
|
let rec really_input (self : #t) buf i len =
|
|
if len > 0 then (
|
|
let n = input self buf i len in
|
|
if n = 0 then raise End_of_file;
|
|
(really_input [@tailrec]) self buf (i + n) (len - n)
|
|
)
|
|
|
|
let really_input_string self n : string =
|
|
let buf = Bytes.create n in
|
|
really_input self buf 0 n;
|
|
Bytes.unsafe_to_string buf
|
|
|
|
let copy_into ?(buf = Bytes.create _default_buf_size) (ic : #t) (oc : IO_out.t)
|
|
: unit =
|
|
let continue = ref true in
|
|
while !continue do
|
|
let len = input ic buf 0 (Bytes.length buf) in
|
|
if len = 0 then
|
|
continue := false
|
|
else
|
|
IO_out.output oc buf 0 len
|
|
done
|
|
|
|
let concat (l0 : t list) : t =
|
|
let l = ref l0 in
|
|
let rec input b i len : int =
|
|
match !l with
|
|
| [] -> 0
|
|
| ic :: tl ->
|
|
let n = ic#input b i len in
|
|
if n > 0 then
|
|
n
|
|
else (
|
|
l := tl;
|
|
input b i len
|
|
)
|
|
in
|
|
let close () = List.iter close l0 in
|
|
create ~close ~input ()
|
|
|
|
let input_all ?(buf = Bytes.create 128) (self : #t) : string =
|
|
let buf = ref buf in
|
|
let i = ref 0 in
|
|
|
|
let[@inline] full_ () = !i = Bytes.length !buf in
|
|
|
|
let grow_ () =
|
|
let old_size = Bytes.length !buf in
|
|
let new_size = min Sys.max_string_length (old_size + (old_size / 4) + 10) in
|
|
if old_size = new_size then
|
|
failwith "input_all: maximum input size exceeded";
|
|
let new_buf = Bytes.extend !buf 0 (new_size - old_size) in
|
|
buf := new_buf
|
|
in
|
|
|
|
let rec loop () =
|
|
if full_ () then grow_ ();
|
|
let available = Bytes.length !buf - !i in
|
|
let n = input self !buf !i available in
|
|
if n > 0 then (
|
|
i := !i + n;
|
|
(loop [@tailrec]) ()
|
|
)
|
|
in
|
|
loop ();
|
|
|
|
if full_ () then
|
|
Bytes.unsafe_to_string !buf
|
|
else
|
|
Bytes.sub_string !buf 0 !i
|
|
|
|
let of_unix_fd ?(close_noerr = false) ?(buf = Bytes.create _default_buf_size)
|
|
(fd : Unix.file_descr) : t =
|
|
let buf_len = ref 0 in
|
|
let buf_off = ref 0 in
|
|
|
|
let refill () =
|
|
buf_off := 0;
|
|
buf_len := Base.read fd buf 0 (Bytes.length buf)
|
|
in
|
|
|
|
object
|
|
method input b i len : int =
|
|
if !buf_len = 0 then refill ();
|
|
let n = min len !buf_len in
|
|
if n > 0 then (
|
|
Bytes.blit buf !buf_off b i n;
|
|
buf_off := !buf_off + n;
|
|
buf_len := !buf_len - n
|
|
);
|
|
n
|
|
|
|
method close () =
|
|
if close_noerr then (
|
|
try Unix.close fd with _ -> ()
|
|
) else
|
|
Unix.close fd
|
|
end
|