1 //! # Chapter 4: Parsers With Custom Return Types 2 //! 3 //! So far, we have seen mostly functions that take an `&str`, and return a 4 //! `PResult<&str>`. Splitting strings into smaller strings and characters is certainly 5 //! useful, but it's not the only thing winnow is capable of! 6 //! 7 //! A useful operation when parsing is to convert between types; for example 8 //! parsing from `&str` to another primitive, like [`usize`]. 9 //! 10 //! All we need to do for our parser to return a different type is to change 11 //! the type parameter of [`PResult`] to the desired return type. 12 //! For example, to return a `usize`, return a `PResult<usize>`. 13 //! 14 //! One winnow-native way of doing a type conversion is to use the 15 //! [`Parser::parse_to`] combinator 16 //! to convert from a successful parse to a particular type using [`FromStr`]. 17 //! 18 //! The following code converts from a string containing a number to `usize`: 19 //! ```rust 20 //! # use winnow::prelude::*; 21 //! # use winnow::ascii::digit1; 22 //! # 23 //! fn parse_digits(input: &mut &str) -> PResult<usize> { 24 //! digit1 25 //! .parse_to() 26 //! .parse_next(input) 27 //! } 28 //! 29 //! fn main() { 30 //! let mut input = "1024 Hello"; 31 //! 32 //! let output = parse_digits.parse_next(&mut input).unwrap(); 33 //! assert_eq!(input, " Hello"); 34 //! assert_eq!(output, 1024); 35 //! 36 //! assert!(parse_digits(&mut "Z").is_err()); 37 //! } 38 //! ``` 39 //! 40 //! `Parser::parse_to` is just a convenient form of [`Parser::try_map`] which we can use to handle 41 //! all radices of numbers: 42 //! ```rust 43 //! # use winnow::prelude::*; 44 //! # use winnow::token::take_while; 45 //! use winnow::combinator::dispatch; 46 //! use winnow::token::take; 47 //! use winnow::combinator::fail; 48 //! 49 //! fn parse_digits(input: &mut &str) -> PResult<usize> { 50 //! dispatch!(take(2usize); 51 //! "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), 52 //! "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), 53 //! "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), 54 //! "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), 55 //! _ => fail, 56 //! ).parse_next(input) 57 //! } 58 //! 59 //! // ... 60 //! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> { 61 //! # take_while(1.., ( 62 //! # ('0'..='1'), 63 //! # )).parse_next(input) 64 //! # } 65 //! # 66 //! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> { 67 //! # take_while(1.., ( 68 //! # ('0'..='7'), 69 //! # )).parse_next(input) 70 //! # } 71 //! # 72 //! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> { 73 //! # take_while(1.., ( 74 //! # ('0'..='9'), 75 //! # )).parse_next(input) 76 //! # } 77 //! # 78 //! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> { 79 //! # take_while(1.., ( 80 //! # ('0'..='9'), 81 //! # ('A'..='F'), 82 //! # ('a'..='f'), 83 //! # )).parse_next(input) 84 //! # } 85 //! 86 //! fn main() { 87 //! let mut input = "0x1a2b Hello"; 88 //! 89 //! let digits = parse_digits.parse_next(&mut input).unwrap(); 90 //! 91 //! assert_eq!(input, " Hello"); 92 //! assert_eq!(digits, 0x1a2b); 93 //! 94 //! assert!(parse_digits(&mut "ghiWorld").is_err()); 95 //! } 96 //! ``` 97 //! 98 //! See also [`Parser`] for more output-modifying parsers. 99 100 #![allow(unused_imports)] 101 use crate::PResult; 102 use crate::Parser; 103 use std::str::FromStr; 104 105 pub use super::chapter_3 as previous; 106 pub use super::chapter_5 as next; 107 pub use crate::_tutorial as table_of_contents; 108