Available on crate feature
unstable-doc only.Expand description
Chapter 7: Integrating the Parser
So far, we’ve highlighted how to incrementally parse, but how do we bring this all together into our application?
Parsers we’ve been working with look like:
pub fn parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
// ...
}
type PResult<O> = Result<
O,
ErrMode<ContextError>
>;- We have to decide what to do about the “remainder” of the
input. - The
ErrMode<ContextError>is not compatible with the rest of the Rust ecosystem. Normally, Rust applications want errors that arestd::error::Error + Send + Sync + 'staticmeaning:- They implement the
std::error::Errortrait - They can be sent across threads
- They are safe to be referenced across threads
- They do not borrow
- They implement the
winnow provides Parser::parse to help with this:
- Ensures we hit
eof - Removes the
ErrModewrapper - Wraps the error in
ParseError- Provides access to the original
inputwith theoffsetof where it failed - Provides a default renderer (via
std::fmt::Display)
- Provides access to the original
use winnow::Parser;
#[derive(Debug, PartialEq, Eq)]
pub struct Hex(usize);
impl std::str::FromStr for Hex {
type Err = String;
fn from_str(input: &str) -> Result<Self, Self::Err> {
parse_digits
.map(Hex)
.parse(input)
.map_err(|e| e.to_string())
}
}
// ...
fn main() {
let input = "0x1a2b";
assert_eq!(input.parse::<Hex>().unwrap(), Hex(0x1a2b));
let input = "0x1a2b Hello";
assert!(input.parse::<Hex>().is_err());
let input = "ghiHello";
assert!(input.parse::<Hex>().is_err());
}