• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! # Chapter 6: Integrating the Parser
2 //!
3 //! So far, we've highlighted how to incrementally parse, but how do we bring this all together
4 //! into our application?
5 //!
6 //! Parsers we've been working with look like:
7 //! ```rust
8 //! # use winnow::error::ContextError;
9 //! # use winnow::error::ErrMode;
10 //! # use winnow::Parser;
11 //! use winnow::PResult;
12 //!
13 //! pub fn parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
14 //!     // ...
15 //! #     Ok("")
16 //! }
17 //! ```
18 //! 1. We have to decide what to do about the "remainder" of the `input`.
19 //! 2. The [`PResult`] is not compatible with the rest of the Rust ecosystem.
20 //!     Normally, Rust applications want errors that are `std::error::Error + Send + Sync + 'static`
21 //!     meaning:
22 //!     - They implement the [`std::error::Error`] trait
23 //!     - They can be sent across threads
24 //!     - They are safe to be referenced across threads
25 //!     - They do not borrow
26 //!
27 //! winnow provides [`Parser::parse`] to help with this:
28 //! - Ensures we hit [`eof`]
29 //! - Converts from [`PResult`] to [`Result`]
30 //! - Wraps the error in [`ParseError`]
31 //!   - For simple cases, [`ParseError`] provides a [`std::fmt::Display`] impl to render the error.
32 //!   - For more involved cases, [`ParseError`] provides the original [`input`][ParseError::input] and the
33 //!     [`offset`][ParseError::offset] of where it failed so you can capture this information in
34 //!     your error, [rendering it as you wish][chapter_7#error-adaptation-and-rendering].
35 //!
36 //! However, [`ParseError`] will still need some level of adaptation to integrate with your
37 //! application's error type (like with `?`).
38 //!
39 //! ```rust
40 //! # use winnow::prelude::*;
41 //! # use winnow::token::take_while;
42 //! # use winnow::combinator::dispatch;
43 //! # use winnow::token::take;
44 //! # use winnow::combinator::fail;
45 //! use winnow::Parser;
46 //!
47 //! #[derive(Debug, PartialEq, Eq)]
48 //! pub struct Hex(usize);
49 //!
50 //! impl std::str::FromStr for Hex {
51 //!     type Err = anyhow::Error;
52 //!
53 //!     fn from_str(input: &str) -> Result<Self, Self::Err> {
54 //!         parse_digits
55 //!             .map(Hex)
56 //!             .parse(input)
57 //!             .map_err(|e| anyhow::format_err!("{e}"))
58 //!     }
59 //! }
60 //!
61 //! // ...
62 //! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<usize> {
63 //! #     dispatch!(take(2usize);
64 //! #         "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
65 //! #         "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
66 //! #         "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
67 //! #         "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
68 //! #         _ => fail,
69 //! #     ).parse_next(input)
70 //! # }
71 //! #
72 //! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
73 //! #     take_while(1.., (
74 //! #         ('0'..='1'),
75 //! #     )).parse_next(input)
76 //! # }
77 //! #
78 //! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
79 //! #     take_while(1.., (
80 //! #         ('0'..='7'),
81 //! #     )).parse_next(input)
82 //! # }
83 //! #
84 //! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
85 //! #     take_while(1.., (
86 //! #         ('0'..='9'),
87 //! #     )).parse_next(input)
88 //! # }
89 //! #
90 //! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
91 //! #     take_while(1.., (
92 //! #         ('0'..='9'),
93 //! #         ('A'..='F'),
94 //! #         ('a'..='f'),
95 //! #     )).parse_next(input)
96 //! # }
97 //!
98 //! fn main() {
99 //!     let input = "0x1a2b";
100 //!     assert_eq!(input.parse::<Hex>().unwrap(), Hex(0x1a2b));
101 //!
102 //!     let input = "0x1a2b Hello";
103 //!     assert!(input.parse::<Hex>().is_err());
104 //!     let input = "ghiHello";
105 //!     assert!(input.parse::<Hex>().is_err());
106 //! }
107 //! ```
108 
109 #![allow(unused_imports)]
110 use super::chapter_1;
111 use super::chapter_7;
112 use crate::combinator::eof;
113 use crate::error::ErrMode;
114 use crate::error::InputError;
115 use crate::error::ParseError;
116 use crate::PResult;
117 use crate::Parser;
118 
119 pub use super::chapter_5 as previous;
120 pub use super::chapter_7 as next;
121 pub use crate::_tutorial as table_of_contents;
122