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