winnow/ascii/
mod.rs

1//! Character specific parsers and combinators
2//!
3//! Functions recognizing specific characters
4
5#[cfg(test)]
6mod tests;
7
8use crate::lib::std::ops::{Add, Shl};
9
10use crate::combinator::alt;
11use crate::combinator::cut_err;
12use crate::combinator::dispatch;
13use crate::combinator::empty;
14use crate::combinator::fail;
15use crate::combinator::opt;
16use crate::combinator::trace;
17use crate::error::ParserError;
18use crate::error::{ErrMode, ErrorKind, Needed};
19use crate::stream::FindSlice;
20use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial};
21use crate::stream::{Compare, CompareResult};
22use crate::token::any;
23use crate::token::one_of;
24use crate::token::take_until;
25use crate::token::take_while;
26use crate::PResult;
27use 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)]
48pub struct Caseless<T>(pub T);
49
50impl Caseless<&str> {
51    /// Get the byte-representation of this case-insensitive value
52    #[inline(always)]
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)]
100pub fn crlf<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
101where
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)]
155pub fn till_line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
156where
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
171fn till_line_ending_<I, E: ParserError<I>, const PARTIAL: bool>(
172    input: &mut I,
173) -> PResult<<I as Stream>::Slice, E>
174where
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::Incomplete(err)) => {
184            return Err(ErrMode::Incomplete(err));
185        }
186        Err(_) => input.finish(),
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)]
246pub fn line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
247where
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)]
296pub fn newline<I, Error: ParserError<I>>(input: &mut I) -> PResult<char, Error>
297where
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)]
347pub fn tab<Input, Error>(input: &mut Input) -> PResult<char, Error>
348where
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)]
399pub fn alpha0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
400where
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)]
452pub fn alpha1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
453where
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)]
506pub fn digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
507where
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)]
576pub fn digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
577where
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)]
629pub fn hex_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
630where
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)]
683pub fn hex_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
684where
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)]
736pub fn oct_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
737where
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)]
790pub fn oct_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
791where
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)]
843pub fn alphanumeric0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
844where
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)]
896pub fn alphanumeric1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
897where
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)]
936pub fn space0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
937where
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)]
989pub fn space1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
990where
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)]
1042pub fn multispace0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
1043where
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)]
1095pub fn multispace1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error>
1096where
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")]
1125pub fn dec_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1126where
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`]
1148pub trait Uint: Sized {
1149    #[doc(hidden)]
1150    fn try_from_dec_uint(slice: &str) -> Option<Self>;
1151}
1152
1153impl Uint for u8 {
1154    fn try_from_dec_uint(slice: &str) -> Option<Self> {
1155        slice.parse().ok()
1156    }
1157}
1158
1159impl Uint for u16 {
1160    fn try_from_dec_uint(slice: &str) -> Option<Self> {
1161        slice.parse().ok()
1162    }
1163}
1164
1165impl Uint for u32 {
1166    fn try_from_dec_uint(slice: &str) -> Option<Self> {
1167        slice.parse().ok()
1168    }
1169}
1170
1171impl Uint for u64 {
1172    fn try_from_dec_uint(slice: &str) -> Option<Self> {
1173        slice.parse().ok()
1174    }
1175}
1176
1177impl Uint for u128 {
1178    fn try_from_dec_uint(slice: &str) -> Option<Self> {
1179        slice.parse().ok()
1180    }
1181}
1182
1183impl Uint for usize {
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")]
1210pub fn dec_int<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1211where
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`]
1238pub trait Int: Sized {
1239    #[doc(hidden)]
1240    fn try_from_dec_int(slice: &str) -> Option<Self>;
1241}
1242
1243impl Int for i8 {
1244    fn try_from_dec_int(slice: &str) -> Option<Self> {
1245        slice.parse().ok()
1246    }
1247}
1248
1249impl Int for i16 {
1250    fn try_from_dec_int(slice: &str) -> Option<Self> {
1251        slice.parse().ok()
1252    }
1253}
1254
1255impl Int for i32 {
1256    fn try_from_dec_int(slice: &str) -> Option<Self> {
1257        slice.parse().ok()
1258    }
1259}
1260
1261impl Int for i64 {
1262    fn try_from_dec_int(slice: &str) -> Option<Self> {
1263        slice.parse().ok()
1264    }
1265}
1266
1267impl Int for i128 {
1268    fn try_from_dec_int(slice: &str) -> Option<Self> {
1269        slice.parse().ok()
1270    }
1271}
1272
1273impl Int for isize {
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]
1329pub fn hex_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1330where
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`]
1387pub trait HexUint:
1388    Default + Shl<Self, Output = Self> + Add<Self, Output = Self> + From<u8>
1389{
1390    #[doc(hidden)]
1391    fn max_nibbles(_: sealed::SealedMarker) -> usize;
1392}
1393
1394impl HexUint for u8 {
1395    #[inline(always)]
1396    fn max_nibbles(_: sealed::SealedMarker) -> usize {
1397        2
1398    }
1399}
1400
1401impl HexUint for u16 {
1402    #[inline(always)]
1403    fn max_nibbles(_: sealed::SealedMarker) -> usize {
1404        4
1405    }
1406}
1407
1408impl HexUint for u32 {
1409    #[inline(always)]
1410    fn max_nibbles(_: sealed::SealedMarker) -> usize {
1411        8
1412    }
1413}
1414
1415impl HexUint for u64 {
1416    #[inline(always)]
1417    fn max_nibbles(_: sealed::SealedMarker) -> usize {
1418        16
1419    }
1420}
1421
1422impl HexUint for u128 {
1423    #[inline(always)]
1424    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
1485pub fn float<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error>
1486where
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
1502fn take_float_or_exceptions<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
1503where
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
1530fn take_float<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
1531where
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)]
1601pub 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>
1606where
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)]
1624pub 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>
1629where
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
1638fn 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>
1644where
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
1680fn 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>
1686where
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)]
1793pub 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>
1798where
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
1814fn 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>
1820where
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
1853fn 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>
1859where
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
1893mod sealed {
1894    pub struct SealedMarker;
1895}