• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Character specific parsers and combinators
2 //!
3 //! Functions recognizing specific characters
4 
5 #[cfg(test)]
6 mod tests;
7 
8 use crate::lib::std::ops::{Add, Shl};
9 
10 use crate::combinator::alt;
11 use crate::combinator::cut_err;
12 use crate::combinator::dispatch;
13 use crate::combinator::empty;
14 use crate::combinator::fail;
15 use crate::combinator::opt;
16 use crate::combinator::trace;
17 use crate::error::ParserError;
18 use crate::error::{ErrMode, ErrorKind, Needed};
19 use crate::stream::FindSlice;
20 use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial};
21 use crate::stream::{Compare, CompareResult};
22 use crate::token::any;
23 use crate::token::one_of;
24 use crate::token::take_until;
25 use crate::token::take_while;
26 use crate::PResult;
27 use crate::Parser;
28 
29 /// Mark a value as case-insensitive for ASCII characters
30 ///
31 /// # Example
32 /// ```rust
33 /// # use winnow::prelude::*;
34 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
35 /// # use winnow::ascii::Caseless;
36 ///
37 /// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
38 ///   Caseless("hello").parse_next(s)
39 /// }
40 ///
41 /// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello")));
42 /// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello")));
43 /// assert_eq!(parser.parse_peek("HeLlo, World!"), Ok((", World!", "HeLlo")));
44 /// assert_eq!(parser.parse_peek("Some"), Err(ErrMode::Backtrack(InputError::new("Some", ErrorKind::Tag))));
45 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
46 /// ```
47 #[derive(Copy, Clone, Debug)]
48 pub struct Caseless<T>(pub T);
49 
50 impl Caseless<&str> {
51     /// Get the byte-representation of this case-insensitive value
52     #[inline(always)]
as_bytes(&self) -> Caseless<&[u8]>53     pub fn as_bytes(&self) -> Caseless<&[u8]> {
54         Caseless(self.0.as_bytes())
55     }
56 }
57 
58 /// Recognizes the string `"\r\n"`.
59 ///
60 /// *Complete version*: Will return an error if there's not enough input data.
61 ///
62 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
63 ///
64 /// # Effective Signature
65 ///
66 /// Assuming you are parsing a `&str` [Stream]:
67 /// ```rust
68 /// # use winnow::prelude::*;;
69 /// pub fn crlf<'i>(input: &mut &'i str) -> PResult<&'i str>
70 /// # {
71 /// #     winnow::ascii::crlf.parse_next(input)
72 /// # }
73 /// ```
74 ///
75 /// # Example
76 ///
77 /// ```
78 /// # use winnow::prelude::*;
79 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
80 /// # use winnow::ascii::crlf;
81 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
82 ///     crlf.parse_next(input)
83 /// }
84 ///
85 /// assert_eq!(parser.parse_peek("\r\nc"), Ok(("c", "\r\n")));
86 /// assert_eq!(parser.parse_peek("ab\r\nc"), Err(ErrMode::Backtrack(InputError::new("ab\r\nc", ErrorKind::Tag))));
87 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
88 /// ```
89 ///
90 /// ```
91 /// # use winnow::prelude::*;
92 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
93 /// # use winnow::Partial;
94 /// # use winnow::ascii::crlf;
95 /// assert_eq!(crlf::<_, InputError<_>>.parse_peek(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n")));
96 /// assert_eq!(crlf::<_, InputError<_>>.parse_peek(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("ab\r\nc"), ErrorKind::Tag))));
97 /// assert_eq!(crlf::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(2))));
98 /// ```
99 #[inline(always)]
crlf<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream + Compare<&'static str>, Error: ParserError<Input>,100 pub fn crlf<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
101 where
102     Input: StreamIsPartial + Stream + Compare<&'static str>,
103     Error: ParserError<Input>,
104 {
105     trace("crlf", "\r\n").parse_next(input)
106 }
107 
108 /// Recognizes a string of any char except `"\r\n"` or `"\n"`.
109 ///
110 /// *Complete version*: Will return an error if there's not enough input data.
111 ///
112 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
113 ///
114 /// # Effective Signature
115 ///
116 /// Assuming you are parsing a `&str` [Stream]:
117 /// ```rust
118 /// # use winnow::prelude::*;;
119 /// pub fn till_line_ending<'i>(input: &mut &'i str) -> PResult<&'i str>
120 /// # {
121 /// #     winnow::ascii::till_line_ending.parse_next(input)
122 /// # }
123 /// ```
124 ///
125 /// # Example
126 ///
127 /// ```
128 /// # use winnow::prelude::*;
129 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
130 /// # use winnow::ascii::till_line_ending;
131 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
132 ///     till_line_ending.parse_next(input)
133 /// }
134 ///
135 /// assert_eq!(parser.parse_peek("ab\r\nc"), Ok(("\r\nc", "ab")));
136 /// assert_eq!(parser.parse_peek("ab\nc"), Ok(("\nc", "ab")));
137 /// assert_eq!(parser.parse_peek("abc"), Ok(("", "abc")));
138 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
139 /// assert_eq!(parser.parse_peek("a\rb\nc"), Err(ErrMode::Backtrack(InputError::new("\rb\nc", ErrorKind::Tag ))));
140 /// assert_eq!(parser.parse_peek("a\rbc"), Err(ErrMode::Backtrack(InputError::new("\rbc", ErrorKind::Tag ))));
141 /// ```
142 ///
143 /// ```
144 /// # use winnow::prelude::*;
145 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
146 /// # use winnow::Partial;
147 /// # use winnow::ascii::till_line_ending;
148 /// assert_eq!(till_line_ending::<_, InputError<_>>.parse_peek(Partial::new("ab\r\nc")), Ok((Partial::new("\r\nc"), "ab")));
149 /// assert_eq!(till_line_ending::<_, InputError<_>>.parse_peek(Partial::new("abc")), Err(ErrMode::Incomplete(Needed::Unknown)));
150 /// assert_eq!(till_line_ending::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::Unknown)));
151 /// assert_eq!(till_line_ending::<_, InputError<_>>.parse_peek(Partial::new("a\rb\nc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("\rb\nc"), ErrorKind::Tag ))));
152 /// assert_eq!(till_line_ending::<_, InputError<_>>.parse_peek(Partial::new("a\rbc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("\rbc"), ErrorKind::Tag ))));
153 /// ```
154 #[inline(always)]
till_line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream + Compare<&'static str> + FindSlice<(char, char)>, <Input as Stream>::Token: AsChar + Clone, Error: ParserError<Input>,155 pub fn till_line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
156 where
157     Input: StreamIsPartial + Stream + Compare<&'static str> + FindSlice<(char, char)>,
158     <Input as Stream>::Token: AsChar + Clone,
159     Error: ParserError<Input>,
160 {
161     trace("till_line_ending", move |input: &mut Input| {
162         if <Input as StreamIsPartial>::is_partial_supported() {
163             till_line_ending_::<_, _, true>(input)
164         } else {
165             till_line_ending_::<_, _, false>(input)
166         }
167     })
168     .parse_next(input)
169 }
170 
till_line_ending_<I, E: ParserError<I>, const PARTIAL: bool>( input: &mut I, ) -> PResult<<I as Stream>::Slice, E> where I: StreamIsPartial, I: Stream, I: Compare<&'static str>, I: FindSlice<(char, char)>, <I as Stream>::Token: AsChar + Clone,171 fn till_line_ending_<I, E: ParserError<I>, const PARTIAL: bool>(
172     input: &mut I,
173 ) -> PResult<<I as Stream>::Slice, E>
174 where
175     I: StreamIsPartial,
176     I: Stream,
177     I: Compare<&'static str>,
178     I: FindSlice<(char, char)>,
179     <I as Stream>::Token: AsChar + Clone,
180 {
181     let res = match take_until(0.., ('\r', '\n')).parse_next(input) {
182         Ok(slice) => slice,
183         Err(ErrMode::Backtrack(_)) => input.finish(),
184         Err(err) => {
185             return Err(err);
186         }
187     };
188     if matches!(input.compare("\r"), CompareResult::Ok(_)) {
189         let comp = input.compare("\r\n");
190         match comp {
191             CompareResult::Ok(_) => {}
192             CompareResult::Incomplete if PARTIAL && input.is_partial() => {
193                 return Err(ErrMode::Incomplete(Needed::Unknown));
194             }
195             CompareResult::Incomplete | CompareResult::Error => {
196                 let e: ErrorKind = ErrorKind::Tag;
197                 return Err(ErrMode::from_error_kind(input, e));
198             }
199         }
200     }
201     Ok(res)
202 }
203 
204 /// Recognizes an end of line (both `"\n"` and `"\r\n"`).
205 ///
206 /// *Complete version*: Will return an error if there's not enough input data.
207 ///
208 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
209 ///
210 /// # Effective Signature
211 ///
212 /// Assuming you are parsing a `&str` [Stream]:
213 /// ```rust
214 /// # use winnow::prelude::*;;
215 /// pub fn line_ending<'i>(input: &mut &'i str) -> PResult<&'i str>
216 /// # {
217 /// #     winnow::ascii::line_ending.parse_next(input)
218 /// # }
219 /// ```
220 ///
221 /// # Example
222 ///
223 /// ```
224 /// # use winnow::prelude::*;
225 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
226 /// # use winnow::ascii::line_ending;
227 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
228 ///     line_ending.parse_next(input)
229 /// }
230 ///
231 /// assert_eq!(parser.parse_peek("\r\nc"), Ok(("c", "\r\n")));
232 /// assert_eq!(parser.parse_peek("ab\r\nc"), Err(ErrMode::Backtrack(InputError::new("ab\r\nc", ErrorKind::Tag))));
233 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
234 /// ```
235 ///
236 /// ```
237 /// # use winnow::prelude::*;
238 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
239 /// # use winnow::Partial;
240 /// # use winnow::ascii::line_ending;
241 /// assert_eq!(line_ending::<_, InputError<_>>.parse_peek(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n")));
242 /// assert_eq!(line_ending::<_, InputError<_>>.parse_peek(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("ab\r\nc"), ErrorKind::Tag))));
243 /// assert_eq!(line_ending::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
244 /// ```
245 #[inline(always)]
line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream + Compare<&'static str>, Error: ParserError<Input>,246 pub fn line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
247 where
248     Input: StreamIsPartial + Stream + Compare<&'static str>,
249     Error: ParserError<Input>,
250 {
251     trace("line_ending", alt(("\n", "\r\n"))).parse_next(input)
252 }
253 
254 /// Matches a newline character `'\n'`.
255 ///
256 /// *Complete version*: Will return an error if there's not enough input data.
257 ///
258 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
259 ///
260 /// # Effective Signature
261 ///
262 /// Assuming you are parsing a `&str` [Stream]:
263 /// ```rust
264 /// # use winnow::prelude::*;;
265 /// pub fn newline(input: &mut &str) -> PResult<char>
266 /// # {
267 /// #     winnow::ascii::newline.parse_next(input)
268 /// # }
269 /// ```
270 ///
271 /// # Example
272 ///
273 /// ```
274 /// # use winnow::prelude::*;
275 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
276 /// # use winnow::ascii::newline;
277 /// fn parser<'s>(input: &mut &'s str) -> PResult<char, InputError<&'s str>> {
278 ///     newline.parse_next(input)
279 /// }
280 ///
281 /// assert_eq!(parser.parse_peek("\nc"), Ok(("c", '\n')));
282 /// assert_eq!(parser.parse_peek("\r\nc"), Err(ErrMode::Backtrack(InputError::new("\r\nc", ErrorKind::Tag))));
283 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
284 /// ```
285 ///
286 /// ```
287 /// # use winnow::prelude::*;
288 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
289 /// # use winnow::Partial;
290 /// # use winnow::ascii::newline;
291 /// assert_eq!(newline::<_, InputError<_>>.parse_peek(Partial::new("\nc")), Ok((Partial::new("c"), '\n')));
292 /// assert_eq!(newline::<_, InputError<_>>.parse_peek(Partial::new("\r\nc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("\r\nc"), ErrorKind::Tag))));
293 /// assert_eq!(newline::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
294 /// ```
295 #[inline(always)]
newline<I, Error: ParserError<I>>(input: &mut I) -> PResult<char, Error> where I: StreamIsPartial, I: Stream, I: Compare<char>,296 pub fn newline<I, Error: ParserError<I>>(input: &mut I) -> PResult<char, Error>
297 where
298     I: StreamIsPartial,
299     I: Stream,
300     I: Compare<char>,
301 {
302     trace("newline", '\n').parse_next(input)
303 }
304 
305 /// Matches a tab character `'\t'`.
306 ///
307 /// *Complete version*: Will return an error if there's not enough input data.
308 ///
309 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
310 ///
311 /// # Effective Signature
312 ///
313 /// Assuming you are parsing a `&str` [Stream]:
314 /// ```rust
315 /// # use winnow::prelude::*;;
316 /// pub fn tab(input: &mut &str) -> PResult<char>
317 /// # {
318 /// #     winnow::ascii::tab.parse_next(input)
319 /// # }
320 /// ```
321 ///
322 /// # Example
323 ///
324 /// ```
325 /// # use winnow::prelude::*;
326 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
327 /// # use winnow::ascii::tab;
328 /// fn parser<'s>(input: &mut &'s str) -> PResult<char, InputError<&'s str>> {
329 ///     tab.parse_next(input)
330 /// }
331 ///
332 /// assert_eq!(parser.parse_peek("\tc"), Ok(("c", '\t')));
333 /// assert_eq!(parser.parse_peek("\r\nc"), Err(ErrMode::Backtrack(InputError::new("\r\nc", ErrorKind::Tag))));
334 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
335 /// ```
336 ///
337 /// ```
338 /// # use winnow::prelude::*;
339 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
340 /// # use winnow::Partial;
341 /// # use winnow::ascii::tab;
342 /// assert_eq!(tab::<_, InputError<_>>.parse_peek(Partial::new("\tc")), Ok((Partial::new("c"), '\t')));
343 /// assert_eq!(tab::<_, InputError<_>>.parse_peek(Partial::new("\r\nc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("\r\nc"), ErrorKind::Tag))));
344 /// assert_eq!(tab::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
345 /// ```
346 #[inline(always)]
tab<Input, Error>(input: &mut Input) -> PResult<char, Error> where Input: StreamIsPartial + Stream + Compare<char>, Error: ParserError<Input>,347 pub fn tab<Input, Error>(input: &mut Input) -> PResult<char, Error>
348 where
349     Input: StreamIsPartial + Stream + Compare<char>,
350     Error: ParserError<Input>,
351 {
352     trace("tab", '\t').parse_next(input)
353 }
354 
355 /// Recognizes zero or more lowercase and uppercase ASCII alphabetic characters: `'a'..='z'`, `'A'..='Z'`
356 ///
357 /// *Complete version*: Will return the whole input if no terminating token is found (a non
358 /// alphabetic character).
359 ///
360 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
361 /// or if no terminating token is found (a non alphabetic character).
362 ///
363 /// # Effective Signature
364 ///
365 /// Assuming you are parsing a `&str` [Stream]:
366 /// ```rust
367 /// # use winnow::prelude::*;;
368 /// pub fn alpha0<'i>(input: &mut &'i str) -> PResult<&'i str>
369 /// # {
370 /// #     winnow::ascii::alpha0.parse_next(input)
371 /// # }
372 /// ```
373 ///
374 /// # Example
375 ///
376 /// ```
377 /// # use winnow::prelude::*;
378 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
379 /// # use winnow::ascii::alpha0;
380 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
381 ///     alpha0.parse_next(input)
382 /// }
383 ///
384 /// assert_eq!(parser.parse_peek("ab1c"), Ok(("1c", "ab")));
385 /// assert_eq!(parser.parse_peek("1c"), Ok(("1c", "")));
386 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
387 /// ```
388 ///
389 /// ```
390 /// # use winnow::prelude::*;
391 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
392 /// # use winnow::Partial;
393 /// # use winnow::ascii::alpha0;
394 /// assert_eq!(alpha0::<_, InputError<_>>.parse_peek(Partial::new("ab1c")), Ok((Partial::new("1c"), "ab")));
395 /// assert_eq!(alpha0::<_, InputError<_>>.parse_peek(Partial::new("1c")), Ok((Partial::new("1c"), "")));
396 /// assert_eq!(alpha0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
397 /// ```
398 #[inline(always)]
alpha0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,399 pub fn alpha0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
400 where
401     Input: StreamIsPartial + Stream,
402     <Input as Stream>::Token: AsChar,
403     Error: ParserError<Input>,
404 {
405     trace("alpha0", take_while(0.., AsChar::is_alpha)).parse_next(input)
406 }
407 
408 /// Recognizes one or more lowercase and uppercase ASCII alphabetic characters: `'a'..='z'`, `'A'..='Z'`
409 ///
410 /// *Complete version*: Will return an error if there's not enough input data,
411 /// or the whole input if no terminating token is found  (a non alphabetic character).
412 ///
413 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
414 /// or if no terminating token is found (a non alphabetic character).
415 ///
416 /// # Effective Signature
417 ///
418 /// Assuming you are parsing a `&str` [Stream]:
419 /// ```rust
420 /// # use winnow::prelude::*;;
421 /// pub fn alpha1<'i>(input: &mut &'i str) -> PResult<&'i str>
422 /// # {
423 /// #     winnow::ascii::alpha1.parse_next(input)
424 /// # }
425 /// ```
426 ///
427 /// # Example
428 ///
429 /// ```
430 /// # use winnow::prelude::*;
431 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
432 /// # use winnow::ascii::alpha1;
433 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
434 ///     alpha1.parse_next(input)
435 /// }
436 ///
437 /// assert_eq!(parser.parse_peek("aB1c"), Ok(("1c", "aB")));
438 /// assert_eq!(parser.parse_peek("1c"), Err(ErrMode::Backtrack(InputError::new("1c", ErrorKind::Slice))));
439 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
440 /// ```
441 ///
442 /// ```
443 /// # use winnow::prelude::*;
444 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
445 /// # use winnow::Partial;
446 /// # use winnow::ascii::alpha1;
447 /// assert_eq!(alpha1::<_, InputError<_>>.parse_peek(Partial::new("aB1c")), Ok((Partial::new("1c"), "aB")));
448 /// assert_eq!(alpha1::<_, InputError<_>>.parse_peek(Partial::new("1c")), Err(ErrMode::Backtrack(InputError::new(Partial::new("1c"), ErrorKind::Slice))));
449 /// assert_eq!(alpha1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
450 /// ```
451 #[inline(always)]
alpha1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,452 pub fn alpha1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
453 where
454     Input: StreamIsPartial + Stream,
455     <Input as Stream>::Token: AsChar,
456     Error: ParserError<Input>,
457 {
458     trace("alpha1", take_while(1.., AsChar::is_alpha)).parse_next(input)
459 }
460 
461 /// Recognizes zero or more ASCII numerical characters: `'0'..='9'`
462 ///
463 /// *Complete version*: Will return an error if there's not enough input data,
464 /// or the whole input if no terminating token is found (a non digit character).
465 ///
466 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
467 /// or if no terminating token is found (a non digit character).
468 ///
469 /// # Effective Signature
470 ///
471 /// Assuming you are parsing a `&str` [Stream]:
472 /// ```rust
473 /// # use winnow::prelude::*;;
474 /// pub fn digit0<'i>(input: &mut &'i str) -> PResult<&'i str>
475 /// # {
476 /// #     winnow::ascii::digit0.parse_next(input)
477 /// # }
478 /// ```
479 ///
480 /// # Example
481 ///
482 /// ```
483 /// # use winnow::prelude::*;
484 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
485 /// # use winnow::ascii::digit0;
486 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
487 ///     digit0.parse_next(input)
488 /// }
489 ///
490 /// assert_eq!(parser.parse_peek("21c"), Ok(("c", "21")));
491 /// assert_eq!(parser.parse_peek("21"), Ok(("", "21")));
492 /// assert_eq!(parser.parse_peek("a21c"), Ok(("a21c", "")));
493 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
494 /// ```
495 ///
496 /// ```
497 /// # use winnow::prelude::*;
498 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
499 /// # use winnow::Partial;
500 /// # use winnow::ascii::digit0;
501 /// assert_eq!(digit0::<_, InputError<_>>.parse_peek(Partial::new("21c")), Ok((Partial::new("c"), "21")));
502 /// assert_eq!(digit0::<_, InputError<_>>.parse_peek(Partial::new("a21c")), Ok((Partial::new("a21c"), "")));
503 /// assert_eq!(digit0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
504 /// ```
505 #[inline(always)]
digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,506 pub fn digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
507 where
508     Input: StreamIsPartial + Stream,
509     <Input as Stream>::Token: AsChar,
510     Error: ParserError<Input>,
511 {
512     trace("digit0", take_while(0.., AsChar::is_dec_digit)).parse_next(input)
513 }
514 
515 /// Recognizes one or more ASCII numerical characters: `'0'..='9'`
516 ///
517 /// *Complete version*: Will return an error if there's not enough input data,
518 /// or the whole input if no terminating token is found (a non digit character).
519 ///
520 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
521 /// or if no terminating token is found (a non digit character).
522 ///
523 /// # Effective Signature
524 ///
525 /// Assuming you are parsing a `&str` [Stream]:
526 /// ```rust
527 /// # use winnow::prelude::*;;
528 /// pub fn digit1<'i>(input: &mut &'i str) -> PResult<&'i str>
529 /// # {
530 /// #     winnow::ascii::digit1.parse_next(input)
531 /// # }
532 /// ```
533 ///
534 /// # Example
535 ///
536 /// ```
537 /// # use winnow::prelude::*;
538 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
539 /// # use winnow::ascii::digit1;
540 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
541 ///     digit1.parse_next(input)
542 /// }
543 ///
544 /// assert_eq!(parser.parse_peek("21c"), Ok(("c", "21")));
545 /// assert_eq!(parser.parse_peek("c1"), Err(ErrMode::Backtrack(InputError::new("c1", ErrorKind::Slice))));
546 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
547 /// ```
548 ///
549 /// ```
550 /// # use winnow::prelude::*;
551 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
552 /// # use winnow::Partial;
553 /// # use winnow::ascii::digit1;
554 /// assert_eq!(digit1::<_, InputError<_>>.parse_peek(Partial::new("21c")), Ok((Partial::new("c"), "21")));
555 /// assert_eq!(digit1::<_, InputError<_>>.parse_peek(Partial::new("c1")), Err(ErrMode::Backtrack(InputError::new(Partial::new("c1"), ErrorKind::Slice))));
556 /// assert_eq!(digit1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
557 /// ```
558 ///
559 /// ## Parsing an integer
560 ///
561 /// You can use `digit1` in combination with [`Parser::try_map`] to parse an integer:
562 ///
563 /// ```
564 /// # use winnow::prelude::*;
565 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed, Parser};
566 /// # use winnow::ascii::digit1;
567 /// fn parser<'s>(input: &mut &'s str) -> PResult<u32, InputError<&'s str>> {
568 ///   digit1.try_map(str::parse).parse_next(input)
569 /// }
570 ///
571 /// assert_eq!(parser.parse_peek("416"), Ok(("", 416)));
572 /// assert_eq!(parser.parse_peek("12b"), Ok(("b", 12)));
573 /// assert!(parser.parse_peek("b").is_err());
574 /// ```
575 #[inline(always)]
digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,576 pub fn digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
577 where
578     Input: StreamIsPartial + Stream,
579     <Input as Stream>::Token: AsChar,
580     Error: ParserError<Input>,
581 {
582     trace("digit1", take_while(1.., AsChar::is_dec_digit)).parse_next(input)
583 }
584 
585 /// Recognizes zero or more ASCII hexadecimal numerical characters: `'0'..='9'`, `'A'..='F'`,
586 /// `'a'..='f'`
587 ///
588 /// *Complete version*: Will return the whole input if no terminating token is found (a non hexadecimal digit character).
589 ///
590 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
591 /// or if no terminating token is found (a non hexadecimal digit character).
592 ///
593 /// # Effective Signature
594 ///
595 /// Assuming you are parsing a `&str` [Stream]:
596 /// ```rust
597 /// # use winnow::prelude::*;;
598 /// pub fn hex_digit0<'i>(input: &mut &'i str) -> PResult<&'i str>
599 /// # {
600 /// #     winnow::ascii::hex_digit0.parse_next(input)
601 /// # }
602 /// ```
603 ///
604 /// # Example
605 ///
606 /// ```
607 /// # use winnow::prelude::*;
608 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
609 /// # use winnow::ascii::hex_digit0;
610 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
611 ///     hex_digit0.parse_next(input)
612 /// }
613 ///
614 /// assert_eq!(parser.parse_peek("21cZ"), Ok(("Z", "21c")));
615 /// assert_eq!(parser.parse_peek("Z21c"), Ok(("Z21c", "")));
616 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
617 /// ```
618 ///
619 /// ```
620 /// # use winnow::prelude::*;
621 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
622 /// # use winnow::Partial;
623 /// # use winnow::ascii::hex_digit0;
624 /// assert_eq!(hex_digit0::<_, InputError<_>>.parse_peek(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c")));
625 /// assert_eq!(hex_digit0::<_, InputError<_>>.parse_peek(Partial::new("Z21c")), Ok((Partial::new("Z21c"), "")));
626 /// assert_eq!(hex_digit0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
627 /// ```
628 #[inline(always)]
hex_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,629 pub fn hex_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
630 where
631     Input: StreamIsPartial + Stream,
632     <Input as Stream>::Token: AsChar,
633     Error: ParserError<Input>,
634 {
635     trace("hex_digit0", take_while(0.., AsChar::is_hex_digit)).parse_next(input)
636 }
637 
638 /// Recognizes one or more ASCII hexadecimal numerical characters: `'0'..='9'`, `'A'..='F'`,
639 /// `'a'..='f'`
640 ///
641 /// *Complete version*: Will return an error if there's not enough input data,
642 /// or the whole input if no terminating token is found (a non hexadecimal digit character).
643 ///
644 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
645 /// or if no terminating token is found (a non hexadecimal digit character).
646 ///
647 /// # Effective Signature
648 ///
649 /// Assuming you are parsing a `&str` [Stream]:
650 /// ```rust
651 /// # use winnow::prelude::*;;
652 /// pub fn hex_digit1<'i>(input: &mut &'i str) -> PResult<&'i str>
653 /// # {
654 /// #     winnow::ascii::hex_digit1.parse_next(input)
655 /// # }
656 /// ```
657 ///
658 /// # Example
659 ///
660 /// ```
661 /// # use winnow::prelude::*;
662 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
663 /// # use winnow::ascii::hex_digit1;
664 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
665 ///     hex_digit1.parse_next(input)
666 /// }
667 ///
668 /// assert_eq!(parser.parse_peek("21cZ"), Ok(("Z", "21c")));
669 /// assert_eq!(parser.parse_peek("H2"), Err(ErrMode::Backtrack(InputError::new("H2", ErrorKind::Slice))));
670 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
671 /// ```
672 ///
673 /// ```
674 /// # use winnow::prelude::*;
675 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
676 /// # use winnow::Partial;
677 /// # use winnow::ascii::hex_digit1;
678 /// assert_eq!(hex_digit1::<_, InputError<_>>.parse_peek(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c")));
679 /// assert_eq!(hex_digit1::<_, InputError<_>>.parse_peek(Partial::new("H2")), Err(ErrMode::Backtrack(InputError::new(Partial::new("H2"), ErrorKind::Slice))));
680 /// assert_eq!(hex_digit1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
681 /// ```
682 #[inline(always)]
hex_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,683 pub fn hex_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
684 where
685     Input: StreamIsPartial + Stream,
686     <Input as Stream>::Token: AsChar,
687     Error: ParserError<Input>,
688 {
689     trace("hex_digit1", take_while(1.., AsChar::is_hex_digit)).parse_next(input)
690 }
691 
692 /// Recognizes zero or more octal characters: `'0'..='7'`
693 ///
694 /// *Complete version*: Will return the whole input if no terminating token is found (a non octal
695 /// digit character).
696 ///
697 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
698 /// or if no terminating token is found (a non octal digit character).
699 ///
700 /// # Effective Signature
701 ///
702 /// Assuming you are parsing a `&str` [Stream]:
703 /// ```rust
704 /// # use winnow::prelude::*;;
705 /// pub fn oct_digit0<'i>(input: &mut &'i str) -> PResult<&'i str>
706 /// # {
707 /// #     winnow::ascii::oct_digit0.parse_next(input)
708 /// # }
709 /// ```
710 ///
711 /// # Example
712 ///
713 /// ```
714 /// # use winnow::prelude::*;
715 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
716 /// # use winnow::ascii::oct_digit0;
717 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
718 ///     oct_digit0.parse_next(input)
719 /// }
720 ///
721 /// assert_eq!(parser.parse_peek("21cZ"), Ok(("cZ", "21")));
722 /// assert_eq!(parser.parse_peek("Z21c"), Ok(("Z21c", "")));
723 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
724 /// ```
725 ///
726 /// ```
727 /// # use winnow::prelude::*;
728 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
729 /// # use winnow::Partial;
730 /// # use winnow::ascii::oct_digit0;
731 /// assert_eq!(oct_digit0::<_, InputError<_>>.parse_peek(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21")));
732 /// assert_eq!(oct_digit0::<_, InputError<_>>.parse_peek(Partial::new("Z21c")), Ok((Partial::new("Z21c"), "")));
733 /// assert_eq!(oct_digit0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
734 /// ```
735 #[inline(always)]
oct_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial, Input: Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,736 pub fn oct_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
737 where
738     Input: StreamIsPartial,
739     Input: Stream,
740     <Input as Stream>::Token: AsChar,
741     Error: ParserError<Input>,
742 {
743     trace("oct_digit0", take_while(0.., AsChar::is_oct_digit)).parse_next(input)
744 }
745 
746 /// Recognizes one or more octal characters: `'0'..='7'`
747 ///
748 /// *Complete version*: Will return an error if there's not enough input data,
749 /// or the whole input if no terminating token is found (a non octal digit character).
750 ///
751 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
752 /// or if no terminating token is found (a non octal digit character).
753 ///
754 /// # Effective Signature
755 ///
756 /// Assuming you are parsing a `&str` [Stream]:
757 /// ```rust
758 /// # use winnow::prelude::*;;
759 /// pub fn oct_digit1<'i>(input: &mut &'i str) -> PResult<&'i str>
760 /// # {
761 /// #     winnow::ascii::oct_digit1.parse_next(input)
762 /// # }
763 /// ```
764 ///
765 /// # Example
766 ///
767 /// ```
768 /// # use winnow::prelude::*;
769 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
770 /// # use winnow::ascii::oct_digit1;
771 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
772 ///     oct_digit1.parse_next(input)
773 /// }
774 ///
775 /// assert_eq!(parser.parse_peek("21cZ"), Ok(("cZ", "21")));
776 /// assert_eq!(parser.parse_peek("H2"), Err(ErrMode::Backtrack(InputError::new("H2", ErrorKind::Slice))));
777 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
778 /// ```
779 ///
780 /// ```
781 /// # use winnow::prelude::*;
782 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
783 /// # use winnow::Partial;
784 /// # use winnow::ascii::oct_digit1;
785 /// assert_eq!(oct_digit1::<_, InputError<_>>.parse_peek(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21")));
786 /// assert_eq!(oct_digit1::<_, InputError<_>>.parse_peek(Partial::new("H2")), Err(ErrMode::Backtrack(InputError::new(Partial::new("H2"), ErrorKind::Slice))));
787 /// assert_eq!(oct_digit1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
788 /// ```
789 #[inline(always)]
oct_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,790 pub fn oct_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
791 where
792     Input: StreamIsPartial + Stream,
793     <Input as Stream>::Token: AsChar,
794     Error: ParserError<Input>,
795 {
796     trace("oct_digit0", take_while(1.., AsChar::is_oct_digit)).parse_next(input)
797 }
798 
799 /// Recognizes zero or more ASCII numerical and alphabetic characters: `'a'..='z'`, `'A'..='Z'`, `'0'..='9'`
800 ///
801 /// *Complete version*: Will return the whole input if no terminating token is found (a non
802 /// alphanumerical character).
803 ///
804 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
805 /// or if no terminating token is found (a non alphanumerical character).
806 ///
807 /// # Effective Signature
808 ///
809 /// Assuming you are parsing a `&str` [Stream]:
810 /// ```rust
811 /// # use winnow::prelude::*;;
812 /// pub fn alphanumeric0<'i>(input: &mut &'i str) -> PResult<&'i str>
813 /// # {
814 /// #     winnow::ascii::alphanumeric0.parse_next(input)
815 /// # }
816 /// ```
817 ///
818 /// # Example
819 ///
820 /// ```
821 /// # use winnow::prelude::*;
822 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
823 /// # use winnow::ascii::alphanumeric0;
824 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
825 ///     alphanumeric0.parse_next(input)
826 /// }
827 ///
828 /// assert_eq!(parser.parse_peek("21cZ%1"), Ok(("%1", "21cZ")));
829 /// assert_eq!(parser.parse_peek("&Z21c"), Ok(("&Z21c", "")));
830 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
831 /// ```
832 ///
833 /// ```
834 /// # use winnow::prelude::*;
835 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
836 /// # use winnow::Partial;
837 /// # use winnow::ascii::alphanumeric0;
838 /// assert_eq!(alphanumeric0::<_, InputError<_>>.parse_peek(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ")));
839 /// assert_eq!(alphanumeric0::<_, InputError<_>>.parse_peek(Partial::new("&Z21c")), Ok((Partial::new("&Z21c"), "")));
840 /// assert_eq!(alphanumeric0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
841 /// ```
842 #[inline(always)]
alphanumeric0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,843 pub fn alphanumeric0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
844 where
845     Input: StreamIsPartial + Stream,
846     <Input as Stream>::Token: AsChar,
847     Error: ParserError<Input>,
848 {
849     trace("alphanumeric0", take_while(0.., AsChar::is_alphanum)).parse_next(input)
850 }
851 
852 /// Recognizes one or more ASCII numerical and alphabetic characters: `'a'..='z'`, `'A'..='Z'`, `'0'..='9'`
853 ///
854 /// *Complete version*: Will return an error if there's not enough input data,
855 /// or the whole input if no terminating token is found (a non alphanumerical character).
856 ///
857 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
858 /// or if no terminating token is found (a non alphanumerical character).
859 ///
860 /// # Effective Signature
861 ///
862 /// Assuming you are parsing a `&str` [Stream]:
863 /// ```rust
864 /// # use winnow::prelude::*;;
865 /// pub fn alphanumeric1<'i>(input: &mut &'i str) -> PResult<&'i str>
866 /// # {
867 /// #     winnow::ascii::alphanumeric1.parse_next(input)
868 /// # }
869 /// ```
870 ///
871 /// # Example
872 ///
873 /// ```
874 /// # use winnow::prelude::*;
875 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
876 /// # use winnow::ascii::alphanumeric1;
877 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
878 ///     alphanumeric1.parse_next(input)
879 /// }
880 ///
881 /// assert_eq!(parser.parse_peek("21cZ%1"), Ok(("%1", "21cZ")));
882 /// assert_eq!(parser.parse_peek("&H2"), Err(ErrMode::Backtrack(InputError::new("&H2", ErrorKind::Slice))));
883 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
884 /// ```
885 ///
886 /// ```
887 /// # use winnow::prelude::*;
888 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
889 /// # use winnow::Partial;
890 /// # use winnow::ascii::alphanumeric1;
891 /// assert_eq!(alphanumeric1::<_, InputError<_>>.parse_peek(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ")));
892 /// assert_eq!(alphanumeric1::<_, InputError<_>>.parse_peek(Partial::new("&H2")), Err(ErrMode::Backtrack(InputError::new(Partial::new("&H2"), ErrorKind::Slice))));
893 /// assert_eq!(alphanumeric1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
894 /// ```
895 #[inline(always)]
alphanumeric1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,896 pub fn alphanumeric1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
897 where
898     Input: StreamIsPartial + Stream,
899     <Input as Stream>::Token: AsChar,
900     Error: ParserError<Input>,
901 {
902     trace("alphanumeric1", take_while(1.., AsChar::is_alphanum)).parse_next(input)
903 }
904 
905 /// Recognizes zero or more spaces and tabs.
906 ///
907 /// *Complete version*: Will return the whole input if no terminating token is found (a non space
908 /// character).
909 ///
910 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
911 /// or if no terminating token is found (a non space character).
912 ///
913 /// # Effective Signature
914 ///
915 /// Assuming you are parsing a `&str` [Stream]:
916 /// ```rust
917 /// # use winnow::prelude::*;;
918 /// pub fn space0<'i>(input: &mut &'i str) -> PResult<&'i str>
919 /// # {
920 /// #     winnow::ascii::space0.parse_next(input)
921 /// # }
922 /// ```
923 ///
924 /// # Example
925 ///
926 /// ```
927 /// # use winnow::prelude::*;
928 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
929 /// # use winnow::Partial;
930 /// # use winnow::ascii::space0;
931 /// assert_eq!(space0::<_, InputError<_>>.parse_peek(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t")));
932 /// assert_eq!(space0::<_, InputError<_>>.parse_peek(Partial::new("Z21c")), Ok((Partial::new("Z21c"), "")));
933 /// assert_eq!(space0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
934 /// ```
935 #[inline(always)]
space0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,936 pub fn space0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
937 where
938     Input: StreamIsPartial + Stream,
939     <Input as Stream>::Token: AsChar,
940     Error: ParserError<Input>,
941 {
942     trace("space0", take_while(0.., AsChar::is_space)).parse_next(input)
943 }
944 
945 /// Recognizes one or more spaces and tabs.
946 ///
947 /// *Complete version*: Will return the whole input if no terminating token is found (a non space
948 /// character).
949 ///
950 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
951 /// or if no terminating token is found (a non space character).
952 ///
953 /// # Effective Signature
954 ///
955 /// Assuming you are parsing a `&str` [Stream]:
956 /// ```rust
957 /// # use winnow::prelude::*;;
958 /// pub fn space1<'i>(input: &mut &'i str) -> PResult<&'i str>
959 /// # {
960 /// #     winnow::ascii::space1.parse_next(input)
961 /// # }
962 /// ```
963 ///
964 /// # Example
965 ///
966 /// ```
967 /// # use winnow::prelude::*;
968 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
969 /// # use winnow::ascii::space1;
970 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
971 ///     space1.parse_next(input)
972 /// }
973 ///
974 /// assert_eq!(parser.parse_peek(" \t21c"), Ok(("21c", " \t")));
975 /// assert_eq!(parser.parse_peek("H2"), Err(ErrMode::Backtrack(InputError::new("H2", ErrorKind::Slice))));
976 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
977 /// ```
978 ///
979 /// ```
980 /// # use winnow::prelude::*;
981 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
982 /// # use winnow::Partial;
983 /// # use winnow::ascii::space1;
984 /// assert_eq!(space1::<_, InputError<_>>.parse_peek(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t")));
985 /// assert_eq!(space1::<_, InputError<_>>.parse_peek(Partial::new("H2")), Err(ErrMode::Backtrack(InputError::new(Partial::new("H2"), ErrorKind::Slice))));
986 /// assert_eq!(space1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
987 /// ```
988 #[inline(always)]
space1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, Error: ParserError<Input>,989 pub fn space1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
990 where
991     Input: StreamIsPartial + Stream,
992     <Input as Stream>::Token: AsChar,
993     Error: ParserError<Input>,
994 {
995     trace("space1", take_while(1.., AsChar::is_space)).parse_next(input)
996 }
997 
998 /// Recognizes zero or more spaces, tabs, carriage returns and line feeds.
999 ///
1000 /// *Complete version*: will return the whole input if no terminating token is found (a non space
1001 /// character).
1002 ///
1003 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
1004 /// or if no terminating token is found (a non space character).
1005 ///
1006 /// # Effective Signature
1007 ///
1008 /// Assuming you are parsing a `&str` [Stream]:
1009 /// ```rust
1010 /// # use winnow::prelude::*;;
1011 /// pub fn multispace0<'i>(input: &mut &'i str) -> PResult<&'i str>
1012 /// # {
1013 /// #     winnow::ascii::multispace0.parse_next(input)
1014 /// # }
1015 /// ```
1016 ///
1017 /// # Example
1018 ///
1019 /// ```
1020 /// # use winnow::prelude::*;
1021 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1022 /// # use winnow::ascii::multispace0;
1023 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
1024 ///     multispace0.parse_next(input)
1025 /// }
1026 ///
1027 /// assert_eq!(parser.parse_peek(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
1028 /// assert_eq!(parser.parse_peek("Z21c"), Ok(("Z21c", "")));
1029 /// assert_eq!(parser.parse_peek(""), Ok(("", "")));
1030 /// ```
1031 ///
1032 /// ```
1033 /// # use winnow::prelude::*;
1034 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1035 /// # use winnow::Partial;
1036 /// # use winnow::ascii::multispace0;
1037 /// assert_eq!(multispace0::<_, InputError<_>>.parse_peek(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r")));
1038 /// assert_eq!(multispace0::<_, InputError<_>>.parse_peek(Partial::new("Z21c")), Ok((Partial::new("Z21c"), "")));
1039 /// assert_eq!(multispace0::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
1040 /// ```
1041 #[inline(always)]
multispace0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar + Clone, Error: ParserError<Input>,1042 pub fn multispace0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
1043 where
1044     Input: StreamIsPartial + Stream,
1045     <Input as Stream>::Token: AsChar + Clone,
1046     Error: ParserError<Input>,
1047 {
1048     trace("multispace0", take_while(0.., (' ', '\t', '\r', '\n'))).parse_next(input)
1049 }
1050 
1051 /// Recognizes one or more spaces, tabs, carriage returns and line feeds.
1052 ///
1053 /// *Complete version*: will return an error if there's not enough input data,
1054 /// or the whole input if no terminating token is found (a non space character).
1055 ///
1056 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data,
1057 /// or if no terminating token is found (a non space character).
1058 ///
1059 /// # Effective Signature
1060 ///
1061 /// Assuming you are parsing a `&str` [Stream]:
1062 /// ```rust
1063 /// # use winnow::prelude::*;;
1064 /// pub fn multispace1<'i>(input: &mut &'i str) -> PResult<&'i str>
1065 /// # {
1066 /// #     winnow::ascii::multispace1.parse_next(input)
1067 /// # }
1068 /// ```
1069 ///
1070 /// # Example
1071 ///
1072 /// ```
1073 /// # use winnow::prelude::*;
1074 /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
1075 /// # use winnow::ascii::multispace1;
1076 /// fn parser<'s>(input: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
1077 ///     multispace1.parse_next(input)
1078 /// }
1079 ///
1080 /// assert_eq!(parser.parse_peek(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
1081 /// assert_eq!(parser.parse_peek("H2"), Err(ErrMode::Backtrack(InputError::new("H2", ErrorKind::Slice))));
1082 /// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
1083 /// ```
1084 ///
1085 /// ```
1086 /// # use winnow::prelude::*;
1087 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1088 /// # use winnow::Partial;
1089 /// # use winnow::ascii::multispace1;
1090 /// assert_eq!(multispace1::<_, InputError<_>>.parse_peek(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r")));
1091 /// assert_eq!(multispace1::<_, InputError<_>>.parse_peek(Partial::new("H2")), Err(ErrMode::Backtrack(InputError::new(Partial::new("H2"), ErrorKind::Slice))));
1092 /// assert_eq!(multispace1::<_, InputError<_>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
1093 /// ```
1094 #[inline(always)]
multispace1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar + Clone, Error: ParserError<Input>,1095 pub fn multispace1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
1096 where
1097     Input: StreamIsPartial + Stream,
1098     <Input as Stream>::Token: AsChar + Clone,
1099     Error: ParserError<Input>,
1100 {
1101     trace("multispace1", take_while(1.., (' ', '\t', '\r', '\n'))).parse_next(input)
1102 }
1103 
1104 /// Decode a decimal unsigned integer (e.g. [`u32`])
1105 ///
1106 /// *Complete version*: can parse until the end of input.
1107 ///
1108 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
1109 ///
1110 /// # Effective Signature
1111 ///
1112 /// Assuming you are parsing a `&str` [Stream] into a `u32`:
1113 /// ```rust
1114 /// # use winnow::prelude::*;;
1115 /// pub fn dec_uint(input: &mut &str) -> PResult<u32>
1116 /// # {
1117 /// #     winnow::ascii::dec_uint.parse_next(input)
1118 /// # }
1119 /// ```
1120 #[doc(alias = "u8")]
1121 #[doc(alias = "u16")]
1122 #[doc(alias = "u32")]
1123 #[doc(alias = "u64")]
1124 #[doc(alias = "u128")]
dec_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Slice: AsBStr, <Input as Stream>::Token: AsChar + Clone, Output: Uint, Error: ParserError<Input>,1125 pub fn dec_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1126 where
1127     Input: StreamIsPartial + Stream,
1128     <Input as Stream>::Slice: AsBStr,
1129     <Input as Stream>::Token: AsChar + Clone,
1130     Output: Uint,
1131     Error: ParserError<Input>,
1132 {
1133     trace("dec_uint", move |input: &mut Input| {
1134         alt(((one_of('1'..='9'), digit0).void(), one_of('0').void()))
1135             .take()
1136             .verify_map(|s: <Input as Stream>::Slice| {
1137                 let s = s.as_bstr();
1138                 // SAFETY: Only 7-bit ASCII characters are parsed
1139                 let s = unsafe { crate::lib::std::str::from_utf8_unchecked(s) };
1140                 Output::try_from_dec_uint(s)
1141             })
1142             .parse_next(input)
1143     })
1144     .parse_next(input)
1145 }
1146 
1147 /// Metadata for parsing unsigned integers, see [`dec_uint`]
1148 pub trait Uint: Sized {
1149     #[doc(hidden)]
try_from_dec_uint(slice: &str) -> Option<Self>1150     fn try_from_dec_uint(slice: &str) -> Option<Self>;
1151 }
1152 
1153 impl Uint for u8 {
try_from_dec_uint(slice: &str) -> Option<Self>1154     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1155         slice.parse().ok()
1156     }
1157 }
1158 
1159 impl Uint for u16 {
try_from_dec_uint(slice: &str) -> Option<Self>1160     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1161         slice.parse().ok()
1162     }
1163 }
1164 
1165 impl Uint for u32 {
try_from_dec_uint(slice: &str) -> Option<Self>1166     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1167         slice.parse().ok()
1168     }
1169 }
1170 
1171 impl Uint for u64 {
try_from_dec_uint(slice: &str) -> Option<Self>1172     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1173         slice.parse().ok()
1174     }
1175 }
1176 
1177 impl Uint for u128 {
try_from_dec_uint(slice: &str) -> Option<Self>1178     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1179         slice.parse().ok()
1180     }
1181 }
1182 
1183 impl Uint for usize {
try_from_dec_uint(slice: &str) -> Option<Self>1184     fn try_from_dec_uint(slice: &str) -> Option<Self> {
1185         slice.parse().ok()
1186     }
1187 }
1188 
1189 /// Decode a decimal signed integer (e.g. [`i32`])
1190 ///
1191 /// *Complete version*: can parse until the end of input.
1192 ///
1193 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data.
1194 ///
1195 /// # Effective Signature
1196 ///
1197 /// Assuming you are parsing a `&str` [Stream] into an `i32`:
1198 /// ```rust
1199 /// # use winnow::prelude::*;;
1200 /// pub fn dec_int(input: &mut &str) -> PResult<i32>
1201 /// # {
1202 /// #     winnow::ascii::dec_int.parse_next(input)
1203 /// # }
1204 /// ```
1205 #[doc(alias = "i8")]
1206 #[doc(alias = "i16")]
1207 #[doc(alias = "i32")]
1208 #[doc(alias = "i64")]
1209 #[doc(alias = "i128")]
dec_int<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Slice: AsBStr, <Input as Stream>::Token: AsChar + Clone, Output: Int, Error: ParserError<Input>,1210 pub fn dec_int<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1211 where
1212     Input: StreamIsPartial + Stream,
1213     <Input as Stream>::Slice: AsBStr,
1214     <Input as Stream>::Token: AsChar + Clone,
1215     Output: Int,
1216     Error: ParserError<Input>,
1217 {
1218     trace("dec_int", move |input: &mut Input| {
1219         let sign = opt(dispatch! {any.map(AsChar::as_char);
1220             '+' => empty.value(true),
1221             '-' => empty.value(false),
1222             _ => fail,
1223         });
1224         alt(((sign, one_of('1'..='9'), digit0).void(), one_of('0').void()))
1225             .take()
1226             .verify_map(|s: <Input as Stream>::Slice| {
1227                 let s = s.as_bstr();
1228                 // SAFETY: Only 7-bit ASCII characters are parsed
1229                 let s = unsafe { crate::lib::std::str::from_utf8_unchecked(s) };
1230                 Output::try_from_dec_int(s)
1231             })
1232             .parse_next(input)
1233     })
1234     .parse_next(input)
1235 }
1236 
1237 /// Metadata for parsing signed integers, see [`dec_int`]
1238 pub trait Int: Sized {
1239     #[doc(hidden)]
try_from_dec_int(slice: &str) -> Option<Self>1240     fn try_from_dec_int(slice: &str) -> Option<Self>;
1241 }
1242 
1243 impl Int for i8 {
try_from_dec_int(slice: &str) -> Option<Self>1244     fn try_from_dec_int(slice: &str) -> Option<Self> {
1245         slice.parse().ok()
1246     }
1247 }
1248 
1249 impl Int for i16 {
try_from_dec_int(slice: &str) -> Option<Self>1250     fn try_from_dec_int(slice: &str) -> Option<Self> {
1251         slice.parse().ok()
1252     }
1253 }
1254 
1255 impl Int for i32 {
try_from_dec_int(slice: &str) -> Option<Self>1256     fn try_from_dec_int(slice: &str) -> Option<Self> {
1257         slice.parse().ok()
1258     }
1259 }
1260 
1261 impl Int for i64 {
try_from_dec_int(slice: &str) -> Option<Self>1262     fn try_from_dec_int(slice: &str) -> Option<Self> {
1263         slice.parse().ok()
1264     }
1265 }
1266 
1267 impl Int for i128 {
try_from_dec_int(slice: &str) -> Option<Self>1268     fn try_from_dec_int(slice: &str) -> Option<Self> {
1269         slice.parse().ok()
1270     }
1271 }
1272 
1273 impl Int for isize {
try_from_dec_int(slice: &str) -> Option<Self>1274     fn try_from_dec_int(slice: &str) -> Option<Self> {
1275         slice.parse().ok()
1276     }
1277 }
1278 
1279 /// Decode a variable-width hexadecimal integer (e.g. [`u32`])
1280 ///
1281 /// *Complete version*: Will parse until the end of input if it has fewer characters than the type
1282 /// supports.
1283 ///
1284 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if end-of-input
1285 /// is hit before a hard boundary (non-hex character, more characters than supported).
1286 ///
1287 /// # Effective Signature
1288 ///
1289 /// Assuming you are parsing a `&str` [Stream] into a `u32`:
1290 /// ```rust
1291 /// # use winnow::prelude::*;;
1292 /// pub fn hex_uint(input: &mut &str) -> PResult<u32>
1293 /// # {
1294 /// #     winnow::ascii::hex_uint.parse_next(input)
1295 /// # }
1296 /// ```
1297 ///
1298 /// # Example
1299 ///
1300 /// ```rust
1301 /// # use winnow::prelude::*;
1302 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
1303 /// use winnow::ascii::hex_uint;
1304 ///
1305 /// fn parser<'s>(s: &mut &'s [u8]) -> PResult<u32, InputError<&'s [u8]>> {
1306 ///   hex_uint(s)
1307 /// }
1308 ///
1309 /// assert_eq!(parser.parse_peek(&b"01AE"[..]), Ok((&b""[..], 0x01AE)));
1310 /// assert_eq!(parser.parse_peek(&b"abc"[..]), Ok((&b""[..], 0x0ABC)));
1311 /// assert_eq!(parser.parse_peek(&b"ggg"[..]), Err(ErrMode::Backtrack(InputError::new(&b"ggg"[..], ErrorKind::Slice))));
1312 /// ```
1313 ///
1314 /// ```rust
1315 /// # use winnow::prelude::*;
1316 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1317 /// # use winnow::Partial;
1318 /// use winnow::ascii::hex_uint;
1319 ///
1320 /// fn parser<'s>(s: &mut Partial<&'s [u8]>) -> PResult<u32, InputError<Partial<&'s [u8]>>> {
1321 ///   hex_uint(s)
1322 /// }
1323 ///
1324 /// assert_eq!(parser.parse_peek(Partial::new(&b"01AE;"[..])), Ok((Partial::new(&b";"[..]), 0x01AE)));
1325 /// assert_eq!(parser.parse_peek(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1))));
1326 /// assert_eq!(parser.parse_peek(Partial::new(&b"ggg"[..])), Err(ErrMode::Backtrack(InputError::new(Partial::new(&b"ggg"[..]), ErrorKind::Slice))));
1327 /// ```
1328 #[inline]
hex_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> where Input: StreamIsPartial + Stream, <Input as Stream>::Token: AsChar, <Input as Stream>::Slice: AsBStr, Output: HexUint, Error: ParserError<Input>,1329 pub fn hex_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1330 where
1331     Input: StreamIsPartial + Stream,
1332     <Input as Stream>::Token: AsChar,
1333     <Input as Stream>::Slice: AsBStr,
1334     Output: HexUint,
1335     Error: ParserError<Input>,
1336 {
1337     trace("hex_uint", move |input: &mut Input| {
1338         let invalid_offset = input
1339             .offset_for(|c| {
1340                 let c = c.as_char();
1341                 !"0123456789abcdefABCDEF".contains(c)
1342             })
1343             .unwrap_or_else(|| input.eof_offset());
1344         let max_nibbles = Output::max_nibbles(sealed::SealedMarker);
1345         let max_offset = input.offset_at(max_nibbles);
1346         let offset = match max_offset {
1347             Ok(max_offset) => {
1348                 if max_offset < invalid_offset {
1349                     // Overflow
1350                     return Err(ErrMode::from_error_kind(input, ErrorKind::Verify));
1351                 } else {
1352                     invalid_offset
1353                 }
1354             }
1355             Err(_) => {
1356                 if <Input as StreamIsPartial>::is_partial_supported()
1357                     && input.is_partial()
1358                     && invalid_offset == input.eof_offset()
1359                 {
1360                     // Only the next byte is guaranteed required
1361                     return Err(ErrMode::Incomplete(Needed::new(1)));
1362                 } else {
1363                     invalid_offset
1364                 }
1365             }
1366         };
1367         if offset == 0 {
1368             // Must be at least one digit
1369             return Err(ErrMode::from_error_kind(input, ErrorKind::Slice));
1370         }
1371         let parsed = input.next_slice(offset);
1372 
1373         let mut res = Output::default();
1374         for c in parsed.as_bstr() {
1375             let nibble = *c as char;
1376             let nibble = nibble.to_digit(16).unwrap_or(0) as u8;
1377             let nibble = Output::from(nibble);
1378             res = (res << Output::from(4)) + nibble;
1379         }
1380 
1381         Ok(res)
1382     })
1383     .parse_next(input)
1384 }
1385 
1386 /// Metadata for parsing hex numbers, see [`hex_uint`]
1387 pub trait HexUint:
1388     Default + Shl<Self, Output = Self> + Add<Self, Output = Self> + From<u8>
1389 {
1390     #[doc(hidden)]
max_nibbles(_: sealed::SealedMarker) -> usize1391     fn max_nibbles(_: sealed::SealedMarker) -> usize;
1392 }
1393 
1394 impl HexUint for u8 {
1395     #[inline(always)]
max_nibbles(_: sealed::SealedMarker) -> usize1396     fn max_nibbles(_: sealed::SealedMarker) -> usize {
1397         2
1398     }
1399 }
1400 
1401 impl HexUint for u16 {
1402     #[inline(always)]
max_nibbles(_: sealed::SealedMarker) -> usize1403     fn max_nibbles(_: sealed::SealedMarker) -> usize {
1404         4
1405     }
1406 }
1407 
1408 impl HexUint for u32 {
1409     #[inline(always)]
max_nibbles(_: sealed::SealedMarker) -> usize1410     fn max_nibbles(_: sealed::SealedMarker) -> usize {
1411         8
1412     }
1413 }
1414 
1415 impl HexUint for u64 {
1416     #[inline(always)]
max_nibbles(_: sealed::SealedMarker) -> usize1417     fn max_nibbles(_: sealed::SealedMarker) -> usize {
1418         16
1419     }
1420 }
1421 
1422 impl HexUint for u128 {
1423     #[inline(always)]
max_nibbles(_: sealed::SealedMarker) -> usize1424     fn max_nibbles(_: sealed::SealedMarker) -> usize {
1425         32
1426     }
1427 }
1428 
1429 /// Recognizes floating point number in text format and returns a [`f32`] or [`f64`].
1430 ///
1431 /// *Complete version*: Can parse until the end of input.
1432 ///
1433 /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data.
1434 ///
1435 /// # Effective Signature
1436 ///
1437 /// Assuming you are parsing a `&str` [Stream] into an `f64`:
1438 /// ```rust
1439 /// # use winnow::prelude::*;;
1440 /// pub fn float(input: &mut &str) -> PResult<f64>
1441 /// # {
1442 /// #     winnow::ascii::float.parse_next(input)
1443 /// # }
1444 /// ```
1445 ///
1446 /// # Example
1447 ///
1448 /// ```rust
1449 /// # use winnow::prelude::*;
1450 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1451 /// # use winnow::error::Needed::Size;
1452 /// use winnow::ascii::float;
1453 ///
1454 /// fn parser<'s>(s: &mut &'s str) -> PResult<f64, InputError<&'s str>> {
1455 ///   float(s)
1456 /// }
1457 ///
1458 /// assert_eq!(parser.parse_peek("11e-1"), Ok(("", 1.1)));
1459 /// assert_eq!(parser.parse_peek("123E-02"), Ok(("", 1.23)));
1460 /// assert_eq!(parser.parse_peek("123K-01"), Ok(("K-01", 123.0)));
1461 /// assert_eq!(parser.parse_peek("abc"), Err(ErrMode::Backtrack(InputError::new("abc", ErrorKind::Tag))));
1462 /// ```
1463 ///
1464 /// ```rust
1465 /// # use winnow::prelude::*;
1466 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1467 /// # use winnow::error::Needed::Size;
1468 /// # use winnow::Partial;
1469 /// use winnow::ascii::float;
1470 ///
1471 /// fn parser<'s>(s: &mut Partial<&'s str>) -> PResult<f64, InputError<Partial<&'s str>>> {
1472 ///   float(s)
1473 /// }
1474 ///
1475 /// assert_eq!(parser.parse_peek(Partial::new("11e-1 ")), Ok((Partial::new(" "), 1.1)));
1476 /// assert_eq!(parser.parse_peek(Partial::new("11e-1")), Err(ErrMode::Incomplete(Needed::new(1))));
1477 /// assert_eq!(parser.parse_peek(Partial::new("123E-02")), Err(ErrMode::Incomplete(Needed::new(1))));
1478 /// assert_eq!(parser.parse_peek(Partial::new("123K-01")), Ok((Partial::new("K-01"), 123.0)));
1479 /// assert_eq!(parser.parse_peek(Partial::new("abc")), Err(ErrMode::Backtrack(InputError::new(Partial::new("abc"), ErrorKind::Tag))));
1480 /// ```
1481 #[inline(always)]
1482 #[doc(alias = "f32")]
1483 #[doc(alias = "double")]
1484 #[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
float<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> where Input: StreamIsPartial + Stream + Compare<Caseless<&'static str>> + Compare<char> + AsBStr, <Input as Stream>::Slice: ParseSlice<Output>, <Input as Stream>::Token: AsChar + Clone, <Input as Stream>::IterOffsets: Clone, Error: ParserError<Input>,1485 pub fn float<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1486 where
1487     Input: StreamIsPartial + Stream + Compare<Caseless<&'static str>> + Compare<char> + AsBStr,
1488     <Input as Stream>::Slice: ParseSlice<Output>,
1489     <Input as Stream>::Token: AsChar + Clone,
1490     <Input as Stream>::IterOffsets: Clone,
1491     Error: ParserError<Input>,
1492 {
1493     trace("float", move |input: &mut Input| {
1494         let s = take_float_or_exceptions(input)?;
1495         s.parse_slice()
1496             .ok_or_else(|| ErrMode::from_error_kind(input, ErrorKind::Verify))
1497     })
1498     .parse_next(input)
1499 }
1500 
1501 #[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
take_float_or_exceptions<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E> where I: StreamIsPartial, I: Stream, I: Compare<Caseless<&'static str>>, I: Compare<char>, <I as Stream>::Token: AsChar + Clone, <I as Stream>::IterOffsets: Clone, I: AsBStr,1502 fn take_float_or_exceptions<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
1503 where
1504     I: StreamIsPartial,
1505     I: Stream,
1506     I: Compare<Caseless<&'static str>>,
1507     I: Compare<char>,
1508     <I as Stream>::Token: AsChar + Clone,
1509     <I as Stream>::IterOffsets: Clone,
1510     I: AsBStr,
1511 {
1512     alt((
1513         take_float,
1514         crate::token::literal(Caseless("nan")),
1515         (
1516             opt(one_of(['+', '-'])),
1517             crate::token::literal(Caseless("infinity")),
1518         )
1519             .take(),
1520         (
1521             opt(one_of(['+', '-'])),
1522             crate::token::literal(Caseless("inf")),
1523         )
1524             .take(),
1525     ))
1526     .parse_next(input)
1527 }
1528 
1529 #[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
take_float<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E> where I: StreamIsPartial, I: Stream, I: Compare<char>, <I as Stream>::Token: AsChar + Clone, <I as Stream>::IterOffsets: Clone, I: AsBStr,1530 fn take_float<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
1531 where
1532     I: StreamIsPartial,
1533     I: Stream,
1534     I: Compare<char>,
1535     <I as Stream>::Token: AsChar + Clone,
1536     <I as Stream>::IterOffsets: Clone,
1537     I: AsBStr,
1538 {
1539     (
1540         opt(one_of(['+', '-'])),
1541         alt((
1542             (digit1, opt(('.', opt(digit1)))).void(),
1543             ('.', digit1).void(),
1544         )),
1545         opt((one_of(['e', 'E']), opt(one_of(['+', '-'])), cut_err(digit1))),
1546     )
1547         .take()
1548         .parse_next(input)
1549 }
1550 
1551 /// Recognize the input slice with escaped characters.
1552 ///
1553 /// Arguments:
1554 /// - `normal`: unescapeable characters
1555 ///   - Must not include `control`
1556 /// - `control_char`: e.g. `\` for strings in most languages
1557 /// - `escape`: parse and transform the escaped character
1558 ///
1559 /// Parsing ends when:
1560 /// - `alt(normal, control._char)` [`Backtrack`s][crate::error::ErrMode::Backtrack]
1561 /// - `normal` doesn't advance the input stream
1562 /// - *(complete)* input stream is exhausted
1563 ///
1564 /// See also [`escaped_transform`]
1565 ///
1566 /// # Example
1567 ///
1568 /// ```rust
1569 /// # use winnow::prelude::*;
1570 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed, IResult};
1571 /// # use winnow::ascii::digit1;
1572 /// # use winnow::prelude::*;
1573 /// use winnow::ascii::take_escaped;
1574 /// use winnow::token::one_of;
1575 ///
1576 /// fn esc(s: &str) -> IResult<&str, &str> {
1577 ///   take_escaped(digit1, '\\', one_of(['"', 'n', '\\'])).parse_peek(s)
1578 /// }
1579 ///
1580 /// assert_eq!(esc("123;"), Ok((";", "123")));
1581 /// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#)));
1582 /// ```
1583 ///
1584 /// ```rust
1585 /// # use winnow::prelude::*;
1586 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed, IResult};
1587 /// # use winnow::ascii::digit1;
1588 /// # use winnow::prelude::*;
1589 /// # use winnow::Partial;
1590 /// use winnow::ascii::take_escaped;
1591 /// use winnow::token::one_of;
1592 ///
1593 /// fn esc(s: Partial<&str>) -> IResult<Partial<&str>, &str> {
1594 ///   take_escaped(digit1, '\\', one_of(['"', 'n', '\\'])).parse_peek(s)
1595 /// }
1596 ///
1597 /// assert_eq!(esc(Partial::new("123;")), Ok((Partial::new(";"), "123")));
1598 /// assert_eq!(esc(Partial::new("12\\\"34;")), Ok((Partial::new(";"), "12\\\"34")));
1599 /// ```
1600 #[inline(always)]
take_escaped<'i, Input, Error, Normal, Escapable, NormalOutput, EscapableOutput>( mut normal: Normal, control_char: char, mut escapable: Escapable, ) -> impl Parser<Input, <Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream + Compare<char> + 'i, Normal: Parser<Input, NormalOutput, Error>, Escapable: Parser<Input, EscapableOutput, Error>, Error: ParserError<Input>,1601 pub fn take_escaped<'i, Input, Error, Normal, Escapable, NormalOutput, EscapableOutput>(
1602     mut normal: Normal,
1603     control_char: char,
1604     mut escapable: Escapable,
1605 ) -> impl Parser<Input, <Input as Stream>::Slice, Error>
1606 where
1607     Input: StreamIsPartial + Stream + Compare<char> + 'i,
1608     Normal: Parser<Input, NormalOutput, Error>,
1609     Escapable: Parser<Input, EscapableOutput, Error>,
1610     Error: ParserError<Input>,
1611 {
1612     trace("take_escaped", move |input: &mut Input| {
1613         if <Input as StreamIsPartial>::is_partial_supported() && input.is_partial() {
1614             streaming_escaped_internal(input, &mut normal, control_char, &mut escapable)
1615         } else {
1616             complete_escaped_internal(input, &mut normal, control_char, &mut escapable)
1617         }
1618     })
1619 }
1620 
1621 /// Deprecated, replaced with [`take_escaped`]
1622 #[deprecated(since = "0.6.4", note = "Replaced with `take_escaped`")]
1623 #[inline(always)]
escaped<'i, Input, Error, Normal, Escapable, NormalOutput, EscapableOutput>( normal: Normal, control_char: char, escapable: Escapable, ) -> impl Parser<Input, <Input as Stream>::Slice, Error> where Input: StreamIsPartial + Stream + Compare<char> + 'i, Normal: Parser<Input, NormalOutput, Error>, Escapable: Parser<Input, EscapableOutput, Error>, Error: ParserError<Input>,1624 pub fn escaped<'i, Input, Error, Normal, Escapable, NormalOutput, EscapableOutput>(
1625     normal: Normal,
1626     control_char: char,
1627     escapable: Escapable,
1628 ) -> impl Parser<Input, <Input as Stream>::Slice, Error>
1629 where
1630     Input: StreamIsPartial + Stream + Compare<char> + 'i,
1631     Normal: Parser<Input, NormalOutput, Error>,
1632     Escapable: Parser<Input, EscapableOutput, Error>,
1633     Error: ParserError<Input>,
1634 {
1635     take_escaped(normal, control_char, escapable)
1636 }
1637 
streaming_escaped_internal<I, Error, F, G, O1, O2>( input: &mut I, normal: &mut F, control_char: char, escapable: &mut G, ) -> PResult<<I as Stream>::Slice, Error> where I: StreamIsPartial, I: Stream, I: Compare<char>, F: Parser<I, O1, Error>, G: Parser<I, O2, Error>, Error: ParserError<I>,1638 fn streaming_escaped_internal<I, Error, F, G, O1, O2>(
1639     input: &mut I,
1640     normal: &mut F,
1641     control_char: char,
1642     escapable: &mut G,
1643 ) -> PResult<<I as Stream>::Slice, Error>
1644 where
1645     I: StreamIsPartial,
1646     I: Stream,
1647     I: Compare<char>,
1648     F: Parser<I, O1, Error>,
1649     G: Parser<I, O2, Error>,
1650     Error: ParserError<I>,
1651 {
1652     let start = input.checkpoint();
1653 
1654     while input.eof_offset() > 0 {
1655         let current_len = input.eof_offset();
1656 
1657         match opt(normal.by_ref()).parse_next(input)? {
1658             Some(_) => {
1659                 if input.eof_offset() == current_len {
1660                     let offset = input.offset_from(&start);
1661                     input.reset(&start);
1662                     return Ok(input.next_slice(offset));
1663                 }
1664             }
1665             None => {
1666                 if opt(control_char).parse_next(input)?.is_some() {
1667                     let _ = escapable.parse_next(input)?;
1668                 } else {
1669                     let offset = input.offset_from(&start);
1670                     input.reset(&start);
1671                     return Ok(input.next_slice(offset));
1672                 }
1673             }
1674         }
1675     }
1676 
1677     Err(ErrMode::Incomplete(Needed::Unknown))
1678 }
1679 
complete_escaped_internal<'a, I, Error, F, G, O1, O2>( input: &mut I, normal: &mut F, control_char: char, escapable: &mut G, ) -> PResult<<I as Stream>::Slice, Error> where I: StreamIsPartial, I: Stream, I: Compare<char>, I: 'a, F: Parser<I, O1, Error>, G: Parser<I, O2, Error>, Error: ParserError<I>,1680 fn complete_escaped_internal<'a, I, Error, F, G, O1, O2>(
1681     input: &mut I,
1682     normal: &mut F,
1683     control_char: char,
1684     escapable: &mut G,
1685 ) -> PResult<<I as Stream>::Slice, Error>
1686 where
1687     I: StreamIsPartial,
1688     I: Stream,
1689     I: Compare<char>,
1690     I: 'a,
1691     F: Parser<I, O1, Error>,
1692     G: Parser<I, O2, Error>,
1693     Error: ParserError<I>,
1694 {
1695     let start = input.checkpoint();
1696 
1697     while input.eof_offset() > 0 {
1698         let current_len = input.eof_offset();
1699 
1700         match opt(normal.by_ref()).parse_next(input)? {
1701             Some(_) => {
1702                 if input.eof_offset() == current_len {
1703                     let offset = input.offset_from(&start);
1704                     input.reset(&start);
1705                     return Ok(input.next_slice(offset));
1706                 }
1707             }
1708             None => {
1709                 if opt(control_char).parse_next(input)?.is_some() {
1710                     let _ = escapable.parse_next(input)?;
1711                 } else {
1712                     let offset = input.offset_from(&start);
1713                     input.reset(&start);
1714                     return Ok(input.next_slice(offset));
1715                 }
1716             }
1717         }
1718     }
1719 
1720     input.reset(&start);
1721     Ok(input.finish())
1722 }
1723 
1724 /// Parse escaped characters, unescaping them
1725 ///
1726 /// Arguments:
1727 /// - `normal`: unescapeable characters
1728 ///   - Must not include `control`
1729 /// - `control_char`: e.g. `\` for strings in most languages
1730 /// - `escape`: parse and transform the escaped character
1731 ///
1732 /// Parsing ends when:
1733 /// - `alt(normal, control._char)` [`Backtrack`s][crate::error::ErrMode::Backtrack]
1734 /// - `normal` doesn't advance the input stream
1735 /// - *(complete)* input stream is exhausted
1736 ///
1737 /// # Example
1738 ///
1739 /// ```rust
1740 /// # #[cfg(feature = "std")] {
1741 /// # use winnow::prelude::*;
1742 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1743 /// # use std::str::from_utf8;
1744 /// use winnow::token::literal;
1745 /// use winnow::ascii::escaped_transform;
1746 /// use winnow::ascii::alpha1;
1747 /// use winnow::combinator::alt;
1748 ///
1749 /// fn parser<'s>(input: &mut &'s str) -> PResult<String, InputError<&'s str>> {
1750 ///   escaped_transform(
1751 ///     alpha1,
1752 ///     '\\',
1753 ///     alt((
1754 ///       "\\".value("\\"),
1755 ///       "\"".value("\""),
1756 ///       "n".value("\n"),
1757 ///     ))
1758 ///   ).parse_next(input)
1759 /// }
1760 ///
1761 /// assert_eq!(parser.parse_peek("ab\\\"cd"), Ok(("", String::from("ab\"cd"))));
1762 /// assert_eq!(parser.parse_peek("ab\\ncd"), Ok(("", String::from("ab\ncd"))));
1763 /// # }
1764 /// ```
1765 ///
1766 /// ```
1767 /// # #[cfg(feature = "std")] {
1768 /// # use winnow::prelude::*;
1769 /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1770 /// # use std::str::from_utf8;
1771 /// # use winnow::Partial;
1772 /// use winnow::token::literal;
1773 /// use winnow::ascii::escaped_transform;
1774 /// use winnow::ascii::alpha1;
1775 /// use winnow::combinator::alt;
1776 ///
1777 /// fn parser<'s>(input: &mut Partial<&'s str>) -> PResult<String, InputError<Partial<&'s str>>> {
1778 ///   escaped_transform(
1779 ///     alpha1,
1780 ///     '\\',
1781 ///     alt((
1782 ///       "\\".value("\\"),
1783 ///       "\"".value("\""),
1784 ///       "n".value("\n"),
1785 ///     ))
1786 ///   ).parse_next(input)
1787 /// }
1788 ///
1789 /// assert_eq!(parser.parse_peek(Partial::new("ab\\\"cd\"")), Ok((Partial::new("\""), String::from("ab\"cd"))));
1790 /// # }
1791 /// ```
1792 #[inline(always)]
escaped_transform<Input, Error, Normal, Escape, Output>( mut normal: Normal, control_char: char, mut escape: Escape, ) -> impl Parser<Input, Output, Error> where Input: StreamIsPartial + Stream + Compare<char>, Output: crate::stream::Accumulate<<Input as Stream>::Slice>, Normal: Parser<Input, <Input as Stream>::Slice, Error>, Escape: Parser<Input, <Input as Stream>::Slice, Error>, Error: ParserError<Input>,1793 pub fn escaped_transform<Input, Error, Normal, Escape, Output>(
1794     mut normal: Normal,
1795     control_char: char,
1796     mut escape: Escape,
1797 ) -> impl Parser<Input, Output, Error>
1798 where
1799     Input: StreamIsPartial + Stream + Compare<char>,
1800     Output: crate::stream::Accumulate<<Input as Stream>::Slice>,
1801     Normal: Parser<Input, <Input as Stream>::Slice, Error>,
1802     Escape: Parser<Input, <Input as Stream>::Slice, Error>,
1803     Error: ParserError<Input>,
1804 {
1805     trace("escaped_transform", move |input: &mut Input| {
1806         if <Input as StreamIsPartial>::is_partial_supported() && input.is_partial() {
1807             streaming_escaped_transform_internal(input, &mut normal, control_char, &mut escape)
1808         } else {
1809             complete_escaped_transform_internal(input, &mut normal, control_char, &mut escape)
1810         }
1811     })
1812 }
1813 
streaming_escaped_transform_internal<I, Error, F, G, Output>( input: &mut I, normal: &mut F, control_char: char, transform: &mut G, ) -> PResult<Output, Error> where I: StreamIsPartial, I: Stream, I: Compare<char>, Output: crate::stream::Accumulate<<I as Stream>::Slice>, F: Parser<I, <I as Stream>::Slice, Error>, G: Parser<I, <I as Stream>::Slice, Error>, Error: ParserError<I>,1814 fn streaming_escaped_transform_internal<I, Error, F, G, Output>(
1815     input: &mut I,
1816     normal: &mut F,
1817     control_char: char,
1818     transform: &mut G,
1819 ) -> PResult<Output, Error>
1820 where
1821     I: StreamIsPartial,
1822     I: Stream,
1823     I: Compare<char>,
1824     Output: crate::stream::Accumulate<<I as Stream>::Slice>,
1825     F: Parser<I, <I as Stream>::Slice, Error>,
1826     G: Parser<I, <I as Stream>::Slice, Error>,
1827     Error: ParserError<I>,
1828 {
1829     let mut res = Output::initial(Some(input.eof_offset()));
1830 
1831     while input.eof_offset() > 0 {
1832         let current_len = input.eof_offset();
1833         match opt(normal.by_ref()).parse_next(input)? {
1834             Some(o) => {
1835                 res.accumulate(o);
1836                 if input.eof_offset() == current_len {
1837                     return Ok(res);
1838                 }
1839             }
1840             None => {
1841                 if opt(control_char).parse_next(input)?.is_some() {
1842                     let o = transform.parse_next(input)?;
1843                     res.accumulate(o);
1844                 } else {
1845                     return Ok(res);
1846                 }
1847             }
1848         }
1849     }
1850     Err(ErrMode::Incomplete(Needed::Unknown))
1851 }
1852 
complete_escaped_transform_internal<I, Error, F, G, Output>( input: &mut I, normal: &mut F, control_char: char, transform: &mut G, ) -> PResult<Output, Error> where I: StreamIsPartial, I: Stream, I: Compare<char>, Output: crate::stream::Accumulate<<I as Stream>::Slice>, F: Parser<I, <I as Stream>::Slice, Error>, G: Parser<I, <I as Stream>::Slice, Error>, Error: ParserError<I>,1853 fn complete_escaped_transform_internal<I, Error, F, G, Output>(
1854     input: &mut I,
1855     normal: &mut F,
1856     control_char: char,
1857     transform: &mut G,
1858 ) -> PResult<Output, Error>
1859 where
1860     I: StreamIsPartial,
1861     I: Stream,
1862     I: Compare<char>,
1863     Output: crate::stream::Accumulate<<I as Stream>::Slice>,
1864     F: Parser<I, <I as Stream>::Slice, Error>,
1865     G: Parser<I, <I as Stream>::Slice, Error>,
1866     Error: ParserError<I>,
1867 {
1868     let mut res = Output::initial(Some(input.eof_offset()));
1869 
1870     while input.eof_offset() > 0 {
1871         let current_len = input.eof_offset();
1872 
1873         match opt(normal.by_ref()).parse_next(input)? {
1874             Some(o) => {
1875                 res.accumulate(o);
1876                 if input.eof_offset() == current_len {
1877                     return Ok(res);
1878                 }
1879             }
1880             None => {
1881                 if opt(control_char).parse_next(input)?.is_some() {
1882                     let o = transform.parse_next(input)?;
1883                     res.accumulate(o);
1884                 } else {
1885                     return Ok(res);
1886                 }
1887             }
1888         }
1889     }
1890     Ok(res)
1891 }
1892 
1893 mod sealed {
1894     pub struct SealedMarker;
1895 }
1896