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 let buf = of_flow flow ?initial_size ~max_size in
format_errors (p <* end_of_input) buf 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] [@@inline never]
let bad_offset ~expected actual = let bad_offset ~expected actual =
Fmt.invalid_arg "Sequence is stale (expected to be used at offset %d, but stream is now at %d)" 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}. *) @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 val of_flow : ?initial_size:int -> max_size:int -> #Flow.source -> t
(** [of_flow ~max_size flow] is a buffered reader backed by [flow]. (** [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; next := input;
let i = R.of_flow mock_flow ~max_size in let i = R.of_flow mock_flow ~max_size in
p i 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)". "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 = ()
```