···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Bytesrw adapters for Eio
77+88+ This module provides adapters to create {!Bytesrw.Bytes.Reader.t} and
99+ {!Bytesrw.Bytes.Writer.t} from Eio flows, mirroring the API of
1010+ {!Bytesrw_unix} for Eio's effect-based I/O. *)
1111+1212+open Bytesrw
1313+1414+(** Create a [Bytes.Reader.t] from an Eio source flow.
1515+1616+ Reads directly from the flow without intermediate buffering.
1717+1818+ @param slice_length
1919+ Maximum bytes per slice (default: 65536, which is
2020+ {!Bytes.Slice.unix_io_buffer_size}) *)
2121+let bytes_reader_of_flow ?(slice_length = Bytes.Slice.unix_io_buffer_size)
2222+ (flow : _ Eio.Flow.source) : Bytes.Reader.t =
2323+ let buf_size = Bytes.Slice.check_length slice_length in
2424+ let read () =
2525+ let cstruct = Cstruct.create buf_size in
2626+ match Eio.Flow.single_read flow cstruct with
2727+ | 0 -> Bytes.Slice.eod
2828+ | count ->
2929+ let data_cs = Cstruct.sub cstruct 0 count in
3030+ let buf = Cstruct.to_bytes data_cs in
3131+ Bytes.Slice.make buf ~first:0 ~length:count
3232+ | exception End_of_file -> Bytes.Slice.eod
3333+ in
3434+ Bytes.Reader.make ~slice_length read
3535+3636+(** Create a [Bytes.Reader.t] from an Eio file at [offset].
3737+3838+ Uses pread for random-access reading without loading the whole file.
3939+4040+ @param slice_length Maximum bytes per slice (default: 65536).
4141+ @param length Number of bytes to read (default: to end of file). *)
4242+let pread_reader ?(slice_length = Bytes.Slice.unix_io_buffer_size) ?length
4343+ ~offset (file : _ Eio.File.ro) : Bytes.Reader.t =
4444+ let stat = Eio.File.stat file in
4545+ let file_length = Optint.Int63.to_int stat.size in
4646+ let total = match length with Some n -> n | None -> file_length - offset in
4747+ let pos = ref 0 in
4848+ let buf_size = Bytes.Slice.check_length slice_length in
4949+ let buf = Bytes.create buf_size in
5050+ let read () =
5151+ if !pos >= total then Bytes.Slice.eod
5252+ else
5353+ let len = min buf_size (total - !pos) in
5454+ let cs = Cstruct.create len in
5555+ Eio.File.pread_exact file
5656+ ~file_offset:(Optint.Int63.of_int (offset + !pos))
5757+ [ cs ];
5858+ Cstruct.blit_to_bytes cs 0 buf 0 len;
5959+ pos := !pos + len;
6060+ Bytes.Slice.make buf ~first:0 ~length:len
6161+ in
6262+ Bytes.Reader.make ~slice_length read
6363+6464+(** Create a [Bytes.Writer.t] from an Eio sink flow.
6565+6666+ Writes directly to the flow without intermediate buffering.
6767+6868+ @param slice_length
6969+ Suggested slice length for upstream (default: 65536, which is
7070+ {!Bytes.Slice.unix_io_buffer_size}) *)
7171+let bytes_writer_of_flow ?(slice_length = Bytes.Slice.unix_io_buffer_size)
7272+ (flow : _ Eio.Flow.sink) : Bytes.Writer.t =
7373+ let rec write slice =
7474+ if Bytes.Slice.is_eod slice then ()
7575+ else begin
7676+ let bytes = Bytes.Slice.bytes slice in
7777+ let first = Bytes.Slice.first slice in
7878+ let length = Bytes.Slice.length slice in
7979+ let cstruct = Cstruct.of_bytes ~off:first ~len:length bytes in
8080+ match Eio.Flow.single_write flow [ cstruct ] with
8181+ | count when count = length -> ()
8282+ | count -> write (Option.get (Bytes.Slice.drop count slice))
8383+ end
8484+ in
8585+ Bytes.Writer.make ~slice_length write
+48
lib/bytesrw_eio.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Bytesrw adapters for Eio
77+88+ This module provides adapters to create {!Bytesrw.Bytes.Reader.t} and
99+ {!Bytesrw.Bytes.Writer.t} from Eio flows, mirroring the API of
1010+ [Bytesrw_unix] for Eio's effect-based I/O.
1111+1212+ Unlike the Buf_read/Buf_write wrappers, these adapters read and write
1313+ directly to the flow, allowing bytesrw to handle its own buffering. *)
1414+1515+(** {1 Readers} *)
1616+1717+val bytes_reader_of_flow :
1818+ ?slice_length:int -> _ Eio.Flow.source -> Bytesrw.Bytes.Reader.t
1919+(** [bytes_reader_of_flow flow] creates a reader from an Eio source flow.
2020+2121+ Reads directly from the flow without intermediate buffering.
2222+2323+ @param slice_length Maximum bytes per slice (default: 65536). *)
2424+2525+(** {1 Random-access readers} *)
2626+2727+val pread_reader :
2828+ ?slice_length:int ->
2929+ ?length:int ->
3030+ offset:int ->
3131+ _ Eio.File.ro ->
3232+ Bytesrw.Bytes.Reader.t
3333+(** [pread_reader ~offset file] creates a reader from [file] starting at
3434+ [offset] bytes. Reads via pread on demand — does not load the file into
3535+ memory.
3636+3737+ @param slice_length Maximum bytes per slice (default: 65536).
3838+ @param length Number of bytes to read (default: to end of file). *)
3939+4040+(** {1 Writers} *)
4141+4242+val bytes_writer_of_flow :
4343+ ?slice_length:int -> _ Eio.Flow.sink -> Bytesrw.Bytes.Writer.t
4444+(** [bytes_writer_of_flow flow] creates a writer from an Eio sink flow.
4545+4646+ Writes directly to the flow without intermediate buffering.
4747+4848+ @param slice_length Suggested slice length for upstream (default: 65536). *)