How to add simple context to a Cut error? #584
-
I have found this crate very straightforward to use once I got past the initial learning curve. It's very nicely designed, with great docs and examples. A pleasure to use. Thank you to the author and contributors. But there's one aspect I'm having trouble with - basic error reporting. To start, I have a simple floating point subparser function that simply delegates to a built-in one: fn float(i: &mut &str) -> PResult<f64> {
winnow::ascii::float.parse_next(i)
} This works fine, but I discovered in my application that this also parses "nan" and "inf" into their respective values, and I want to catch this at parse time, as a fatal error. So I changed the function to: fn float_inner(i: &mut &str) -> PResult<f64> {
let f: f64 = winnow::ascii::float.parse_next(i)?;
if f.is_nan() || f.is_infinite() {
Err(ErrMode::Cut(ContextError::new()))
} else {
Ok(f)
}
} This halts the parser on "nan", but the error message shown to the user isn't great - it's just "Parse error" with the line and column, and input line, but no explanation. So I looked to add a context, but to cut a long story short, I just couldn't work out how to add a context to the In the end, inspired by fn float_inner(i: &mut &str) -> PResult<f64> {
let f: f64 = winnow::ascii::float.parse_next(i)?;
if f.is_nan() || f.is_infinite() {
Err(ErrMode::Cut(ContextError::new()))
} else {
Ok(f)
}
}
fn float(i: &mut &str) -> PResult<f64> {
float_inner
.context(StrContext::Label("finite float"))
.parse_next(i)
} This is because, based on the chapter 7 tutorial, I can see how I have a similar issue with these sorts of functions: fn hex_digits(i: &mut &str) -> PResult<u32> {
let s = take_while(1.., |c: char| c.is_ascii_hexdigit()).parse_next(i)?;
u32::from_str_radix(s, 16).map_err(|_| ErrMode::Cut(ContextError::new())) // how to add context here?
} Do I need to wrap those in an outer/inner parse function as well, just to be able to call I feel like there must be a simpler way that I'm missing. I found this discussion: #504 - there's mention of |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
I explored using #[derive(Debug, derive_more::Display, thiserror::Error)]
struct FloatNotFinite {
msg: &'static str,
}
fn float(i: &mut &str) -> PResult<f64> {
let f: f64 = winnow::ascii::float.parse_next(i)?;
if f.is_nan() || f.is_infinite() {
Err(ErrMode::from_external_error(
i,
ErrorKind::Verify,
FloatNotFinite {
msg: "Float not finite",
},
)
.cut())
} else {
Ok(f)
}
} This seems less than ideal just to convey a static |
Beta Was this translation helpful? Give feedback.
-
What about |
Beta Was this translation helpful? Give feedback.
Yes, if directly constructing an error, rather than building on top of an existing error, this is the way to do it.
Ideally, you could do
winnow::ascii::float.verify(|f| f.is_finite()).context(...)
but then thecontext
would apply to failures fromwinnow::ascii::float
and when you only want it to apply toverify
. #180 is the issue for this and I just don't have a good answer beyond writing imperative code like this.