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