Module winnow::_tutorial::chapter_4

source ·
Available on crate feature unstable-doc only.
Expand description

Chapter 4: Parsers With Custom Return Types

So far, we have seen mostly functions that take an &str, and return a PResult<&str>. Splitting strings into smaller strings and characters is certainly useful, but it’s not the only thing winnow is capable of!

A useful operation when parsing is to convert between types; for example parsing from &str to another primitive, like usize.

All we need to do for our parser to return a different type is to change the type parameter of PResult to the desired return type. For example, to return a usize, return a PResult<usize>.

One winnow-native way of doing a type conversion is to use the Parser::parse_to combinator to convert from a successful parse to a particular type using FromStr.

The following code converts from a string containing a number to usize:

fn parse_digits(input: &mut &str) -> PResult<usize> {
    digit1
        .parse_to()
        .parse_next(input)
}

fn main() {
    let mut input = "1024 Hello";

    let output = parse_digits.parse_next(&mut input).unwrap();
    assert_eq!(input, " Hello");
    assert_eq!(output, 1024);

    assert!(parse_digits(&mut "Z").is_err());
}

Parser::parse_to is just a convenient form of Parser::try_map which we can use to handle all radices of numbers:

use winnow::combinator::dispatch;
use winnow::token::take;
use winnow::combinator::fail;

fn parse_digits(input: &mut &str) -> PResult<usize> {
    dispatch!(take(2usize);
        "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
        "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
        "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
        "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
        _ => fail,
    ).parse_next(input)
}

// ...

fn main() {
    let mut input = "0x1a2b Hello";

    let digits = parse_digits.parse_next(&mut input).unwrap();

    assert_eq!(input, " Hello");
    assert_eq!(digits, 0x1a2b);

    assert!(parse_digits(&mut "ghiWorld").is_err());
}

See also Parser for more output-modifying parsers.

Re-exports