Add Buf_read.parse_exn

This commit is contained in:
Thomas Leonard 2022-02-07 09:24:43 +00:00
parent b9a608562d
commit 3b4abcc79c
3 changed files with 65 additions and 0 deletions

View File

@ -278,6 +278,11 @@ let parse ?initial_size ~max_size p flow =
let buf = of_flow flow ?initial_size ~max_size in
format_errors (p <* end_of_input) buf
let parse_exn ?initial_size ~max_size p flow =
match parse ?initial_size ~max_size p flow with
| Ok x -> x
| Error (`Msg m) -> failwith m
[@@inline never]
let bad_offset ~expected actual =
Fmt.invalid_arg "Sequence is stale (expected to be used at offset %d, but stream is now at %d)"

View File

@ -628,6 +628,13 @@ module Buf_read : sig
@param initial_size see {!of_flow}. *)
val parse_exn : ?initial_size:int -> max_size:int -> 'a parser -> #Flow.source -> 'a
(** [parse_exn] wraps {!parse}, but raises [Failure msg] if that returns [Error (`Msg msg)].
Catching exceptions with [parse] and then raising them might seem pointless,
but this has the effect of turning e.g. an [End_of_file] exception into a [Failure]
with a more user-friendly message. *)
val of_flow : ?initial_size:int -> max_size:int -> #Flow.source -> t
(** [of_flow ~max_size flow] is a buffered reader backed by [flow].

View File

@ -51,6 +51,11 @@ let test ?(max_size=10) input p =
next := input;
let i = R.of_flow mock_flow ~max_size in
p i
let parse_exn p flow ~max_size =
match R.parse_exn p flow ~max_size with
| x -> traceln "Ok: %S" x
| exception Failure msg -> traceln "Failure: %s" msg
```
@ -511,3 +516,51 @@ Invalid_argument
"Sequence is stale (expected to be used at offset 4, but stream is now at 8)".
```
## Convenience wrapper
`parse` turns parser errors into friendly messages:
```ocaml
# R.(parse (string "FROM:" *> take_all)) (Eio.Flow.string_source "FROM:A") ~max_size:5;;
- : (string, [> `Msg of string ]) result = Ok "A"
# R.(parse (string "FROM:" *> take_all)) (Eio.Flow.string_source "TO:B") ~max_size:5;;
- : (string, [> `Msg of string ]) result =
Error (`Msg "Expected \"FROM:\" but got \"TO:B\" (at offset 0)")
# R.(parse (string "FROM:" *> take_all)) (Eio.Flow.string_source "FROM:ABCDE") ~max_size:5;;
- : (string, [> `Msg of string ]) result =
Error (`Msg "Buffer size limit exceeded when reading at offset 5")
# R.(parse (string "END")) (Eio.Flow.string_source "ENDING") ~max_size:5;;
- : (unit, [> `Msg of string ]) result =
Error (`Msg "Unexpected data after parsing (at offset 3)")
# R.(parse (string "END")) (Eio.Flow.string_source "E") ~max_size:5;;
- : (unit, [> `Msg of string ]) result =
Error (`Msg "Unexpected end-of-file at offset 1")
```
`parse_exn` is similar, but raises (we then catch it and print it nicely):
```ocaml
# parse_exn R.(string "FROM:" *> take_all) (Eio.Flow.string_source "FROM:A") ~max_size:5;;
+Ok: "A"
- : unit = ()
# parse_exn R.(string "FROM:" *> take_all) (Eio.Flow.string_source "TO:B") ~max_size:5;;
+Failure: Expected "FROM:" but got "TO:B" (at offset 0)
- : unit = ()
# parse_exn R.(string "FROM:" *> take_all) (Eio.Flow.string_source "FROM:ABCDE") ~max_size:5;;
+Failure: Buffer size limit exceeded when reading at offset 5
- : unit = ()
# parse_exn R.(take 3) (Eio.Flow.string_source "ENDING") ~max_size:5;;
+Failure: Unexpected data after parsing (at offset 3)
- : unit = ()
# parse_exn R.(take 3) (Eio.Flow.string_source "E") ~max_size:5;;
+Failure: Unexpected end-of-file at offset 1
- : unit = ()
```