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