Bytesrw adapter for Eio
ocaml codec

Consolidate duplicate hex utilities and crypto functions

- Replace local hex_of_string/string_of_hex with ohex in tests:
- ocaml-spake2/test/test_spake2.ml
- ocaml-matter/test/test_tlv.ml
- ocaml-cbort/test/test_cbort.ml

- Make pase.ml re-export Crypto.sha256/hmac_sha256 instead of duplicating

- Remove odoc-xo rules from ocaml-yamlrw/doc/dune

- Apply ocamlformat to yamlrw, yamlt, bytesrw-eio

+88 -62
+11 -11
src/bytesrw_eio.ml
··· 15 15 16 16 Reads directly from the flow without intermediate buffering. 17 17 18 - @param slice_length Maximum bytes per slice (default: 65536, which is {!Bytes.Slice.unix_io_buffer_size}) *) 19 - let bytes_reader_of_flow 20 - ?(slice_length = Bytes.Slice.unix_io_buffer_size) 21 - (flow : _ Eio.Flow.source) 22 - : Bytes.Reader.t = 18 + @param slice_length 19 + Maximum bytes per slice (default: 65536, which is 20 + {!Bytes.Slice.unix_io_buffer_size}) *) 21 + let bytes_reader_of_flow ?(slice_length = Bytes.Slice.unix_io_buffer_size) 22 + (flow : _ Eio.Flow.source) : Bytes.Reader.t = 23 23 let buf_size = Bytes.Slice.check_length slice_length in 24 24 let read () = 25 25 let cstruct = Cstruct.create buf_size in ··· 37 37 38 38 Writes directly to the flow without intermediate buffering. 39 39 40 - @param slice_length Suggested slice length for upstream (default: 65536, which is {!Bytes.Slice.unix_io_buffer_size}) *) 41 - let bytes_writer_of_flow 42 - ?(slice_length = Bytes.Slice.unix_io_buffer_size) 43 - (flow : _ Eio.Flow.sink) 44 - : Bytes.Writer.t = 40 + @param slice_length 41 + Suggested slice length for upstream (default: 65536, which is 42 + {!Bytes.Slice.unix_io_buffer_size}) *) 43 + let bytes_writer_of_flow ?(slice_length = Bytes.Slice.unix_io_buffer_size) 44 + (flow : _ Eio.Flow.sink) : Bytes.Writer.t = 45 45 let rec write slice = 46 46 if Bytes.Slice.is_eod slice then () 47 47 else begin ··· 49 49 let first = Bytes.Slice.first slice in 50 50 let length = Bytes.Slice.length slice in 51 51 let cstruct = Cstruct.of_bytes ~off:first ~len:length bytes in 52 - match Eio.Flow.single_write flow [cstruct] with 52 + match Eio.Flow.single_write flow [ cstruct ] with 53 53 | count when count = length -> () 54 54 | count -> write (Option.get (Bytes.Slice.drop count slice)) 55 55 end
+2 -6
src/bytesrw_eio.mli
··· 15 15 (** {1 Readers} *) 16 16 17 17 val bytes_reader_of_flow : 18 - ?slice_length:int -> 19 - _ Eio.Flow.source -> 20 - Bytesrw.Bytes.Reader.t 18 + ?slice_length:int -> _ Eio.Flow.source -> Bytesrw.Bytes.Reader.t 21 19 (** [bytes_reader_of_flow flow] creates a reader from an Eio source flow. 22 20 23 21 Reads directly from the flow without intermediate buffering. ··· 27 25 (** {1 Writers} *) 28 26 29 27 val bytes_writer_of_flow : 30 - ?slice_length:int -> 31 - _ Eio.Flow.sink -> 32 - Bytesrw.Bytes.Writer.t 28 + ?slice_length:int -> _ Eio.Flow.sink -> Bytesrw.Bytes.Writer.t 33 29 (** [bytes_writer_of_flow flow] creates a writer from an Eio sink flow. 34 30 35 31 Writes directly to the flow without intermediate buffering.
+75 -45
test/test_bytesrw_eio.ml
··· 12 12 13 13 (* Read first slice *) 14 14 let slice1 = Bytesrw.Bytes.Reader.read reader in 15 - Alcotest.(check bool) "slice is not eod" false (Bytesrw.Bytes.Slice.is_eod slice1); 15 + Alcotest.(check bool) 16 + "slice is not eod" false 17 + (Bytesrw.Bytes.Slice.is_eod slice1); 16 18 17 - let read_data = Bytes.sub_string 18 - (Bytesrw.Bytes.Slice.bytes slice1) 19 - (Bytesrw.Bytes.Slice.first slice1) 20 - (Bytesrw.Bytes.Slice.length slice1) in 19 + let read_data = 20 + Bytes.sub_string 21 + (Bytesrw.Bytes.Slice.bytes slice1) 22 + (Bytesrw.Bytes.Slice.first slice1) 23 + (Bytesrw.Bytes.Slice.length slice1) 24 + in 21 25 Alcotest.(check string) "data matches" test_data read_data; 22 26 23 27 (* Next read should be eod *) 24 28 let slice2 = Bytesrw.Bytes.Reader.read reader in 25 - Alcotest.(check bool) "second read is eod" true (Bytesrw.Bytes.Slice.is_eod slice2) 29 + Alcotest.(check bool) 30 + "second read is eod" true 31 + (Bytesrw.Bytes.Slice.is_eod slice2) 26 32 27 33 (* Test reading with custom slice length *) 28 34 let test_reader_custom_slice_length () = ··· 34 40 35 41 (* Read should respect slice_length as maximum *) 36 42 let slice = Bytesrw.Bytes.Reader.read reader in 37 - Alcotest.(check bool) "slice length <= custom size" true 43 + Alcotest.(check bool) 44 + "slice length <= custom size" true 38 45 (Bytesrw.Bytes.Slice.length slice <= slice_length) 39 46 40 47 (* Test reading empty flow *) ··· 44 51 let reader = Bytesrw_eio.bytes_reader_of_flow flow in 45 52 46 53 let slice = Bytesrw.Bytes.Reader.read reader in 47 - Alcotest.(check bool) "empty flow returns eod" true (Bytesrw.Bytes.Slice.is_eod slice) 54 + Alcotest.(check bool) 55 + "empty flow returns eod" true 56 + (Bytesrw.Bytes.Slice.is_eod slice) 48 57 49 58 (* Test writing to a mock flow *) 50 59 let test_writer_basic () = ··· 55 64 56 65 let test_data = "Hello, World!" in 57 66 let bytes = Bytes.of_string test_data in 58 - let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 67 + let slice = 68 + Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) 69 + in 59 70 60 71 Bytesrw.Bytes.Writer.write writer slice; 61 72 ··· 72 83 73 84 let test_data = "Hello, World!" in 74 85 let bytes = Bytes.of_string test_data in 75 - let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 86 + let slice = 87 + Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) 88 + in 76 89 77 90 Bytesrw.Bytes.Writer.write writer slice; 78 91 79 92 let written = Buffer.contents buf in 80 - Alcotest.(check string) "written data matches regardless of slice_length" test_data written 93 + Alcotest.(check string) 94 + "written data matches regardless of slice_length" test_data written 81 95 82 96 (* Test writing eod slice (should be no-op) *) 83 97 let test_writer_eod () = ··· 112 126 should not be corrupted by subsequent reads *) 113 127 let test_reader_multiple_reads () = 114 128 Eio_main.run @@ fun _env -> 115 - let test_data = "ABCDEFGHIJ" in (* 10 bytes *) 129 + let test_data = "ABCDEFGHIJ" in 130 + (* 10 bytes *) 116 131 let flow = Eio.Flow.string_source test_data in 117 132 let reader = Bytesrw_eio.bytes_reader_of_flow ~slice_length:5 flow in 118 133 119 134 (* Read first 5 bytes *) 120 135 let slice1 = Bytesrw.Bytes.Reader.read reader in 121 136 let bytes1 = Bytesrw.Bytes.Slice.bytes slice1 in 122 - let data1 = Bytes.sub_string bytes1 123 - (Bytesrw.Bytes.Slice.first slice1) 124 - (Bytesrw.Bytes.Slice.length slice1) in 137 + let data1 = 138 + Bytes.sub_string bytes1 139 + (Bytesrw.Bytes.Slice.first slice1) 140 + (Bytesrw.Bytes.Slice.length slice1) 141 + in 125 142 126 143 (* Read next 5 bytes *) 127 144 let slice2 = Bytesrw.Bytes.Reader.read reader in 128 - let data2 = Bytes.sub_string 129 - (Bytesrw.Bytes.Slice.bytes slice2) 130 - (Bytesrw.Bytes.Slice.first slice2) 131 - (Bytesrw.Bytes.Slice.length slice2) in 145 + let data2 = 146 + Bytes.sub_string 147 + (Bytesrw.Bytes.Slice.bytes slice2) 148 + (Bytesrw.Bytes.Slice.first slice2) 149 + (Bytesrw.Bytes.Slice.length slice2) 150 + in 132 151 133 152 (* Critical test: verify first read's data is STILL intact after second read 134 153 This would fail if we were reusing buffers or if Cstruct.to_bytes created a view *) 135 - let data1_check = Bytes.sub_string bytes1 136 - (Bytesrw.Bytes.Slice.first slice1) 137 - (Bytesrw.Bytes.Slice.length slice1) in 154 + let data1_check = 155 + Bytes.sub_string bytes1 156 + (Bytesrw.Bytes.Slice.first slice1) 157 + (Bytesrw.Bytes.Slice.length slice1) 158 + in 138 159 139 160 Alcotest.(check string) "first read" "ABCDE" data1; 140 161 Alcotest.(check string) "second read" "FGHIJ" data2; 141 - Alcotest.(check string) "first read still intact after second" "ABCDE" data1_check 162 + Alcotest.(check string) 163 + "first read still intact after second" "ABCDE" data1_check 142 164 143 165 (* Test round-trip: write then read *) 144 166 let test_roundtrip () = ··· 151 173 let writer = Bytesrw_eio.bytes_writer_of_flow write_flow in 152 174 153 175 let bytes = Bytes.of_string test_data in 154 - let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 176 + let slice = 177 + Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) 178 + in 155 179 Bytesrw.Bytes.Writer.write writer slice; 156 180 157 181 (* Read back from buffer *) ··· 159 183 let reader = Bytesrw_eio.bytes_reader_of_flow read_flow in 160 184 161 185 let read_slice = Bytesrw.Bytes.Reader.read reader in 162 - let read_data = Bytes.sub_string 163 - (Bytesrw.Bytes.Slice.bytes read_slice) 164 - (Bytesrw.Bytes.Slice.first read_slice) 165 - (Bytesrw.Bytes.Slice.length read_slice) in 186 + let read_data = 187 + Bytes.sub_string 188 + (Bytesrw.Bytes.Slice.bytes read_slice) 189 + (Bytesrw.Bytes.Slice.first read_slice) 190 + (Bytesrw.Bytes.Slice.length read_slice) 191 + in 166 192 167 193 Alcotest.(check string) "round-trip data matches" test_data read_data 168 194 169 195 let () = 170 - Alcotest.run "Bytesrw_eio" [ 171 - "reader", [ 172 - Alcotest.test_case "basic read" `Quick test_reader_basic; 173 - Alcotest.test_case "custom slice length" `Quick test_reader_custom_slice_length; 174 - Alcotest.test_case "empty flow" `Quick test_reader_empty; 175 - Alcotest.test_case "multiple reads data isolation" `Quick test_reader_multiple_reads; 176 - ]; 177 - "writer", [ 178 - Alcotest.test_case "basic write" `Quick test_writer_basic; 179 - Alcotest.test_case "custom slice length" `Quick test_writer_custom_slice_length; 180 - Alcotest.test_case "eod write" `Quick test_writer_eod; 181 - Alcotest.test_case "partial slice" `Quick test_writer_partial_slice; 182 - ]; 183 - "integration", [ 184 - Alcotest.test_case "round-trip" `Quick test_roundtrip; 185 - ]; 186 - ] 196 + Alcotest.run "Bytesrw_eio" 197 + [ 198 + ( "reader", 199 + [ 200 + Alcotest.test_case "basic read" `Quick test_reader_basic; 201 + Alcotest.test_case "custom slice length" `Quick 202 + test_reader_custom_slice_length; 203 + Alcotest.test_case "empty flow" `Quick test_reader_empty; 204 + Alcotest.test_case "multiple reads data isolation" `Quick 205 + test_reader_multiple_reads; 206 + ] ); 207 + ( "writer", 208 + [ 209 + Alcotest.test_case "basic write" `Quick test_writer_basic; 210 + Alcotest.test_case "custom slice length" `Quick 211 + test_writer_custom_slice_length; 212 + Alcotest.test_case "eod write" `Quick test_writer_eod; 213 + Alcotest.test_case "partial slice" `Quick test_writer_partial_slice; 214 + ] ); 215 + ("integration", [ Alcotest.test_case "round-trip" `Quick test_roundtrip ]); 216 + ]