1use crate::ascii::AsciiSet;
2use crate::parser::then::Then2;
3use crate::parser::{ParseState, Parser, ParserResult};
4use std::error::Error;
5use std::fmt::{Debug, Display, Formatter};
6
7#[non_exhaustive]
11#[derive(Debug, Copy, Clone)]
12pub enum ParseError {
13 Expected(&'static str),
15 ExpectedLiteral(&'static str),
17 ExpectedByte(u8),
19 ExpectedByteRange(u8, u8),
21 ExpectedOneOf(AsciiSet),
23 ExpectedOneOfBytes(&'static [u8]),
25 ExpectedOneOfLiterals(&'static [&'static str]),
27 ExpectedAtLeastMatches(usize, fn(&u8) -> bool),
29 ExpectedAtMostMatches(usize, fn(&u8) -> bool),
31 ExpectedExactlyMatches(usize, fn(&u8) -> bool),
33 ExpectedLessItems(usize),
35 ExpectedEof(),
37 NumberTooLarge(i128),
39 NumberTooSmall(i128),
41 NumberOutOfRange(),
45 Custom(&'static str),
47}
48
49impl ParseError {
50 #[inline]
51 pub(super) fn too_large(max: impl TryInto<i128>) -> Self {
52 if let Ok(max) = max.try_into() {
53 Self::NumberTooLarge(max)
54 } else {
55 Self::NumberOutOfRange()
56 }
57 }
58
59 #[inline]
60 pub(super) fn too_small(min: impl TryInto<i128>) -> Self {
61 if let Ok(min) = min.try_into() {
62 Self::NumberTooSmall(min)
63 } else {
64 Self::NumberOutOfRange()
65 }
66 }
67}
68
69impl Display for ParseError {
70 #[cold]
71 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72 match *self {
73 ParseError::Expected(x) => write!(f, "expected {x}"),
74 ParseError::ExpectedLiteral(x) => write!(f, "expected {x:?}"),
75 ParseError::ExpectedByte(x) => write!(f, "expected {:?}", x as char),
76 ParseError::ExpectedByteRange(min, max) => {
77 write!(f, "expected {:?}-{:?}", min as char, max as char)
78 }
79 ParseError::ExpectedAtLeastMatches(n, set_fn) => {
80 let set = AsciiSet::from(|b| set_fn(&b));
81 if n == 1 {
82 write!(f, "expected at least 1 character matching {set}")
83 } else {
84 write!(f, "expected at least {n} characters matching {set}")
85 }
86 }
87 ParseError::ExpectedAtMostMatches(n, set_fn) => {
88 let set = AsciiSet::from(|b| set_fn(&b));
89 write!(f, "expected at most {n} characters matching {set}")
90 }
91 ParseError::ExpectedExactlyMatches(n, set_fn) => {
92 let set = AsciiSet::from(|b| set_fn(&b));
93 write!(f, "expected exactly {n} characters matching {set}")
94 }
95 ParseError::ExpectedOneOf(set) => write!(f, "expected one of {set}"),
96 ParseError::ExpectedOneOfBytes(bytes) => {
97 write_one_of(f, bytes.iter().map(|&b| b as char))
98 }
99 ParseError::ExpectedOneOfLiterals(literals) => write_one_of(f, literals.iter()),
100 ParseError::ExpectedEof() => write!(f, "expected end of input"),
101 ParseError::ExpectedLessItems(x) => write!(f, "expected {x} items or less"),
102 ParseError::NumberTooLarge(x) => write!(f, "expected number <= {x}"),
103 ParseError::NumberTooSmall(x) => write!(f, "expected number >= {x}"),
104 ParseError::NumberOutOfRange() => write!(f, "number out of range"),
105 ParseError::Custom(x) => f.write_str(x),
106 }
107 }
108}
109
110impl Error for ParseError {}
111
112fn write_one_of<T: Debug>(
114 f: &mut Formatter<'_>,
115 mut items: impl ExactSizeIterator<Item = T>,
116) -> std::fmt::Result {
117 if items.len() == 1 {
118 return write!(f, "expected {:?}", items.next().unwrap());
119 }
120 write!(f, "expected one of ")?;
121 for (i, item) in items.enumerate() {
122 let separator = if i == 0 { "" } else { ", " };
123 write!(f, "{separator}{item:?}")?;
124 }
125 Ok(())
126}
127
128impl PartialEq for ParseError {
129 fn eq(&self, other: &Self) -> bool {
130 match (*self, *other) {
131 (Self::ExpectedAtLeastMatches(a1, a2), Self::ExpectedAtLeastMatches(b1, b2))
137 | (Self::ExpectedAtMostMatches(a1, a2), Self::ExpectedAtMostMatches(b1, b2))
138 | (Self::ExpectedExactlyMatches(a1, a2), Self::ExpectedExactlyMatches(b1, b2)) => {
139 a1 == b1 && AsciiSet::from(|b| a2(&b)) == AsciiSet::from(|b| b2(&b))
140 }
141
142 (Self::Expected(a), Self::Expected(b))
144 | (Self::ExpectedLiteral(a), Self::ExpectedLiteral(b))
145 | (Self::Custom(a), Self::Custom(b)) => a == b,
146 (Self::ExpectedByte(a), Self::ExpectedByte(b)) => a == b,
147 (Self::ExpectedByteRange(a1, a2), Self::ExpectedByteRange(b1, b2)) => {
148 a1 == b1 && a2 == b2
149 }
150 (Self::ExpectedOneOf(a), Self::ExpectedOneOf(b)) => a == b,
151 (Self::ExpectedOneOfBytes(a), Self::ExpectedOneOfBytes(b)) => a == b,
152 (Self::ExpectedOneOfLiterals(a), Self::ExpectedOneOfLiterals(b)) => a == b,
153 (Self::ExpectedLessItems(a), Self::ExpectedLessItems(b)) => a == b,
154 (Self::ExpectedEof(), Self::ExpectedEof())
155 | (Self::NumberOutOfRange(), Self::NumberOutOfRange()) => true,
156 (Self::NumberTooLarge(a), Self::NumberTooLarge(b))
157 | (Self::NumberTooSmall(a), Self::NumberTooSmall(b)) => a == b,
158
159 (
161 Self::Expected(_)
162 | Self::ExpectedLiteral(_)
163 | Self::ExpectedByte(_)
164 | Self::ExpectedByteRange(_, _)
165 | Self::ExpectedOneOf(_)
166 | Self::ExpectedOneOfBytes(_)
167 | Self::ExpectedOneOfLiterals(_)
168 | Self::ExpectedAtLeastMatches(_, _)
169 | Self::ExpectedAtMostMatches(_, _)
170 | Self::ExpectedExactlyMatches(_, _)
171 | Self::ExpectedLessItems(_)
172 | Self::ExpectedEof()
173 | Self::NumberTooLarge(_)
174 | Self::NumberTooSmall(_)
175 | Self::NumberOutOfRange()
176 | Self::Custom(_),
177 _,
178 ) => false,
179 }
180 }
181}
182
183impl Eq for ParseError {}
184
185impl PartialEq<ParseError> for Box<dyn Error> {
186 fn eq(&self, other: &ParseError) -> bool {
187 if let Some(pe) = self.downcast_ref::<ParseError>() {
188 pe == other
189 } else {
190 false
191 }
192 }
193}
194impl PartialEq<Box<dyn Error>> for ParseError {
195 fn eq(&self, other: &Box<dyn Error>) -> bool {
196 other == self
197 }
198}
199
200#[derive(Copy, Clone)]
201pub struct WithErrorMsg<P> {
202 pub(super) parser: P,
203 pub(super) message: &'static str,
204}
205impl<'i, P: Parser<'i>> Parser<'i> for WithErrorMsg<P> {
206 type Output = P::Output;
207 type Then<T: Parser<'i>> = Then2<Self, T>;
208
209 #[inline]
210 fn parse_ctx(
211 &self,
212 input: &'i [u8],
213 state: &mut ParseState<'i>,
214 commit: &mut bool,
215 tail: bool,
216 ) -> ParserResult<'i, Self::Output> {
217 let prev_remaining = state.error.map(|e| e.1);
218 self.parser
219 .parse_ctx(input, state, commit, tail)
220 .inspect_err(|_| {
221 let remaining = state.error.unwrap().1;
222 if prev_remaining != Some(remaining) {
223 state.error = Some((ParseError::Custom(self.message), remaining));
225 }
226 })
227 }
228}