winnow/_tutorial/chapter_4.rs
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//! [`Result<&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 [`Result`] to the desired return type.
12//! For example, to return a `usize`, return a `Result<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::Result;
22//! # use winnow::ascii::digit1;
23//! #
24//! fn parse_digits(input: &mut &str) -> Result<usize> {
25//! digit1
26//! .parse_to()
27//! .parse_next(input)
28//! }
29//!
30//! fn main() {
31//! let mut input = "1024 Hello";
32//!
33//! let output = parse_digits.parse_next(&mut input).unwrap();
34//! assert_eq!(input, " Hello");
35//! assert_eq!(output, 1024);
36//!
37//! assert!(parse_digits(&mut "Z").is_err());
38//! }
39//! ```
40//!
41//! `Parser::parse_to` is just a convenient form of [`Parser::try_map`] which we can use to handle
42//! all radices of numbers:
43//! ```rust
44//! # use winnow::prelude::*;
45//! # use winnow::Result;
46//! # use winnow::token::take_while;
47//! use winnow::combinator::dispatch;
48//! use winnow::token::take;
49//! use winnow::combinator::fail;
50//!
51//! fn parse_digits(input: &mut &str) -> Result<usize> {
52//! dispatch!(take(2usize);
53//! "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
54//! "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
55//! "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
56//! "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
57//! _ => fail,
58//! ).parse_next(input)
59//! }
60//!
61//! // ...
62//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
63//! # take_while(1.., (
64//! # ('0'..='1'),
65//! # )).parse_next(input)
66//! # }
67//! #
68//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
69//! # take_while(1.., (
70//! # ('0'..='7'),
71//! # )).parse_next(input)
72//! # }
73//! #
74//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
75//! # take_while(1.., (
76//! # ('0'..='9'),
77//! # )).parse_next(input)
78//! # }
79//! #
80//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
81//! # take_while(1.., (
82//! # ('0'..='9'),
83//! # ('A'..='F'),
84//! # ('a'..='f'),
85//! # )).parse_next(input)
86//! # }
87//!
88//! fn main() {
89//! let mut input = "0x1a2b Hello";
90//!
91//! let digits = parse_digits.parse_next(&mut input).unwrap();
92//!
93//! assert_eq!(input, " Hello");
94//! assert_eq!(digits, 0x1a2b);
95//!
96//! assert!(parse_digits(&mut "ghiWorld").is_err());
97//! }
98//! ```
99//!
100//! See also [`Parser`] for more output-modifying parsers.
101
102#![allow(unused_imports)]
103use crate::Parser;
104use crate::Result;
105use std::str::FromStr;
106
107pub use super::chapter_3 as previous;
108pub use super::chapter_5 as next;
109pub use crate::_tutorial as table_of_contents;