Skip to content

Commit dfa3076

Browse files
authored
Merge pull request #399 from Cjen1/add-bigstringaf-ser
Add Buf_read.BE/LE parsers
2 parents 5407ed6 + 9998c86 commit dfa3076

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

fuzz/fuzz_buf_read.ml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,64 @@ module Model = struct
136136
match line t with
137137
| line -> line :: lines t
138138
| exception End_of_file -> []
139+
140+
module BE = struct
141+
let uint16 t = String.get_uint16_be (take 2 t) 0
142+
143+
let uint32 t = String.get_int32_be (take 4 t) 0
144+
145+
let uint48 t =
146+
let s = take 6 t in
147+
let upper_16 = String.get_uint16_be s 0 |> Int64.of_int in
148+
let middle_16 = String.get_uint16_be s 2 |> Int64.of_int in
149+
let lower_16 = String.get_uint16_be s 4 |> Int64.of_int in
150+
Int64.(
151+
add
152+
(shift_left upper_16 32)
153+
(add
154+
(shift_left middle_16 16)
155+
(lower_16))
156+
)
157+
158+
let uint64 t = String.get_int64_be (take 8 t) 0
159+
160+
let float t =
161+
Int32.float_of_bits (
162+
String.get_int32_be (take 4 t) 0)
163+
164+
let double t =
165+
Int64.float_of_bits (
166+
String.get_int64_be (take 8 t) 0)
167+
end
168+
169+
module LE = struct
170+
let uint16 t = String.get_uint16_le (take 2 t) 0
171+
172+
let uint32 t = String.get_int32_le (take 4 t) 0
173+
174+
let uint48 t =
175+
let s = take 6 t in
176+
let lower_16 = String.get_uint16_le s 0 |> Int64.of_int in
177+
let middle_16 = String.get_uint16_le s 2 |> Int64.of_int in
178+
let upper_16 = String.get_uint16_le s 4 |> Int64.of_int in
179+
Int64.(
180+
add
181+
(shift_left upper_16 32)
182+
(add
183+
(shift_left middle_16 16)
184+
(lower_16))
185+
)
186+
187+
let uint64 t = String.get_int64_le (take 8 t) 0
188+
189+
let float t =
190+
Int32.float_of_bits (
191+
String.get_int32_le (take 4 t) 0)
192+
193+
let double t =
194+
Int64.float_of_bits (
195+
String.get_int64_le (take 8 t) 0)
196+
end
139197
end
140198

141199
type op = Op : 'a Crowbar.printer * 'a Buf_read.parser * (Model.t -> 'a) -> op
@@ -162,6 +220,18 @@ let op =
162220
"skip", Crowbar.(map [int]) (fun n -> Op (unit, Buf_read.skip n, Model.skip n));
163221
"end_of_input", Crowbar.const @@ Op (unit, Buf_read.end_of_input, Model.end_of_input);
164222
"lines", Crowbar.const @@ Op (Fmt.Dump.(list string), (Buf_read.(map List.of_seq lines)), Model.lines);
223+
"be_uint16", Crowbar.const @@ Op (Fmt.int, (Buf_read.BE.uint16), Model.BE.uint16);
224+
"be_uint32", Crowbar.const @@ Op (Fmt.int32, (Buf_read.BE.uint32), Model.BE.uint32);
225+
"be_uint48", Crowbar.const @@ Op (Fmt.int64, (Buf_read.BE.uint48), Model.BE.uint48);
226+
"be_uint64", Crowbar.const @@ Op (Fmt.int64, (Buf_read.BE.uint64), Model.BE.uint64);
227+
"be_float", Crowbar.const @@ Op (Fmt.float, (Buf_read.BE.float), Model.BE.float);
228+
"be_double", Crowbar.const @@ Op (Fmt.float, (Buf_read.BE.double), Model.BE.double);
229+
"le_uint16", Crowbar.const @@ Op (Fmt.int, (Buf_read.LE.uint16), Model.LE.uint16);
230+
"le_uint32", Crowbar.const @@ Op (Fmt.int32, (Buf_read.LE.uint32), Model.LE.uint32);
231+
"le_uint48", Crowbar.const @@ Op (Fmt.int64, (Buf_read.LE.uint48), Model.LE.uint48);
232+
"le_uint64", Crowbar.const @@ Op (Fmt.int64, (Buf_read.LE.uint64), Model.LE.uint64);
233+
"le_float", Crowbar.const @@ Op (Fmt.float, (Buf_read.LE.float), Model.LE.float);
234+
"le_double", Crowbar.const @@ Op (Fmt.float, (Buf_read.LE.double), Model.LE.double);
165235
]
166236

167237
let catch f x =

lib_eio/buf_read.ml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,92 @@ let as_flow t =
143143
let get t i =
144144
Bigarray.Array1.get t.buf (t.pos + i)
145145

146+
module BE = struct
147+
let uint16 t =
148+
ensure t 2;
149+
let data = Bigstringaf.get_int16_be t.buf t.pos in
150+
consume t 2;
151+
data
152+
153+
let uint32 t =
154+
ensure t 4;
155+
let data = Bigstringaf.get_int32_be t.buf t.pos in
156+
consume t 4;
157+
data
158+
159+
let uint48 t =
160+
ensure t 6;
161+
let upper_32 = Bigstringaf.get_int32_be t.buf t.pos |> Int64.of_int32 |> Int64.logand 0xffffffffL in
162+
let lower_16 = Bigstringaf.get_int16_be t.buf (t.pos + 4) |> Int64.of_int in
163+
consume t 6;
164+
Int64.(
165+
logor
166+
(lower_16)
167+
(shift_left upper_32 16)
168+
)
169+
170+
let uint64 t =
171+
ensure t 8;
172+
let data = Bigstringaf.get_int64_be t.buf t.pos in
173+
consume t 8;
174+
data
175+
176+
let float t =
177+
ensure t 4;
178+
let data = Bigstringaf.unsafe_get_int32_be t.buf t.pos in
179+
consume t 4;
180+
Int32.float_of_bits data
181+
182+
let double t =
183+
ensure t 8;
184+
let data = Bigstringaf.unsafe_get_int64_be t.buf t.pos in
185+
consume t 8;
186+
Int64.float_of_bits data
187+
end
188+
189+
module LE = struct
190+
let uint16 t =
191+
ensure t 2;
192+
let data = Bigstringaf.get_int16_le t.buf t.pos in
193+
consume t 2;
194+
data
195+
196+
let uint32 t =
197+
ensure t 4;
198+
let data = Bigstringaf.get_int32_le t.buf t.pos in
199+
consume t 4;
200+
data
201+
202+
let uint48 t =
203+
ensure t 6;
204+
let lower_32 = Bigstringaf.get_int32_le t.buf t.pos |> Int64.of_int32 |> Int64.logand 0xffffffffL in
205+
let upper_16 = Bigstringaf.get_int16_le t.buf (t.pos + 4) |> Int64.of_int in
206+
consume t 6;
207+
Int64.(
208+
logor
209+
(shift_left upper_16 32)
210+
lower_32
211+
)
212+
213+
let uint64 t =
214+
ensure t 8;
215+
let data = Bigstringaf.get_int64_le t.buf t.pos in
216+
consume t 8;
217+
data
218+
219+
let float t =
220+
ensure t 4;
221+
let data = Bigstringaf.unsafe_get_int32_le t.buf t.pos in
222+
consume t 4;
223+
Int32.float_of_bits data
224+
225+
let double t =
226+
ensure t 8;
227+
let data = Bigstringaf.unsafe_get_int64_le t.buf t.pos in
228+
consume t 8;
229+
Int64.float_of_bits data
230+
end
231+
146232
let char c t =
147233
ensure t 1;
148234
let c2 = get t 0 in

lib_eio/buf_read.mli

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,48 @@ val string : string -> unit parser
107107
108108
@raise Failure if [s] is not a prefix of the stream. *)
109109

110+
(** Big endian parsers *)
111+
module BE : sig
112+
val uint16 : int parser
113+
(** [uint16] parses the next 2 bytes as the lower 16 bits of an [int] in big-endian byte order *)
114+
115+
val uint32 : int32 parser
116+
(** [uint32] parses the next 4 bytes as an [int32] in big-endian byte order *)
117+
118+
val uint48 : int64 parser
119+
(** [uint48] parses the next 6 bytes as a 48-bit unsigned big-endian integer *)
120+
121+
val uint64 : int64 parser
122+
(** [uint64] parses the next 8 bytes as an [int64] in big-endian byte order *)
123+
124+
val float : float parser
125+
(** [float] parses the next 4 bytes as a [float] in big-endian byte order *)
126+
127+
val double : float parser
128+
(** [double] parses the next 8 bytes as a [float] in big-endian byte order *)
129+
end
130+
131+
(** Little endian parsers *)
132+
module LE : sig
133+
val uint16 : int parser
134+
(** [uint16] parses the next 2 bytes as the lower 16 bits of an [int] in little-endian byte order *)
135+
136+
val uint32 : int32 parser
137+
(** [uint32] parses the next 4 bytes as an [int32] in little-endian byte order *)
138+
139+
val uint48 : int64 parser
140+
(** [uint48] parses the next 6 bytes as a 48-bit unsigned big-endian integer *)
141+
142+
val uint64 : int64 parser
143+
(** [uint64] parses the next 8 bytes as an [int64] in little-endian byte order *)
144+
145+
val float : float parser
146+
(** [float] parses the next 4 bytes as a [float] in little-endian byte order *)
147+
148+
val double : float parser
149+
(** [double] parses the next 8 bytes as a [float] in little-endian byte order *)
150+
end
151+
110152
val take : int -> string parser
111153
(** [take n] takes exactly [n] bytes from the input. *)
112154

tests/buf_reader.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,38 @@ Exception: Failure "skip_while1".
393393
- : string = "bbbccc"
394394
```
395395

396+
## Big Endian
397+
```ocaml
398+
# R.parse_string_exn R.BE.uint16 "\128\001" |> Printf.sprintf "0x%x";;
399+
- : string = "0x8001"
400+
# R.parse_string_exn R.BE.uint32 "\128\064\032\001" |> Printf.sprintf "0x%lx";;
401+
- : string = "0x80402001"
402+
# R.parse_string_exn R.BE.uint48 "\128\064\032\016\008\001" |> Printf.sprintf "0x%Lx";;
403+
- : string = "0x804020100801"
404+
# R.parse_string_exn R.BE.uint64 "\128\064\032\016\008\004\002\001" |> Printf.sprintf "0x%Lx";;
405+
- : string = "0x8040201008040201"
406+
# R.parse_string_exn R.BE.float "\128\064\032\001" |> Printf.sprintf "0x%e";;
407+
- : string = "0x-5.888953e-39"
408+
# R.parse_string_exn R.BE.double "\128\064\032\016\008\004\002\001" |> Printf.sprintf "0x%e";;
409+
- : string = "0x-1.793993e-307"
410+
```
411+
412+
## Little Endian
413+
```ocaml
414+
# R.parse_string_exn R.LE.uint16 "\128\001" |> Printf.sprintf "0x%x";;
415+
- : string = "0x180"
416+
# R.parse_string_exn R.LE.uint32 "\128\064\032\001" |> Printf.sprintf "0x%lx";;
417+
- : string = "0x1204080"
418+
# R.parse_string_exn R.LE.uint48 "\128\064\032\016\008\001" |> Printf.sprintf "0x%Lx";;
419+
- : string = "0x10810204080"
420+
# R.parse_string_exn R.LE.uint64 "\128\064\032\016\008\004\002\001" |> Printf.sprintf "0x%Lx";;
421+
- : string = "0x102040810204080"
422+
# R.parse_string_exn R.LE.float "\128\064\032\001" |> Printf.sprintf "0x%e";;
423+
- : string = "0x2.943364e-38"
424+
# R.parse_string_exn R.LE.double "\128\064\032\016\008\004\002\001" |> Printf.sprintf "0x%e";;
425+
- : string = "0x8.209689e-304"
426+
```
427+
396428
## Take all
397429

398430
```ocaml

0 commit comments

Comments
 (0)