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(name:"crlf", parser:"\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 traceimpl Parser::Slice, …>(name:"till_line_ending", parser: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: ::Slice = match take_until::<_, _, ()>(occurrences:0.., ('\r', '\n')).parse_next(input) {
182 Ok(slice: ::Slice) => slice,
183 Err(ErrMode::Incomplete(err: Needed)) => {
184 return Err(ErrMode::Incomplete(err));
185 }
186 Err(_) => input.finish(),
187 };
188 if matches!(input.compare("\r"), CompareResult::Ok(_)) {
189 let comp: CompareResult = 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, kind: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(name:"line_ending", parser: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(name:"newline", parser:'\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(name:"tab", parser:'\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(name:"alpha0", parser:take_while(occurrences:0.., set: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(name:"alpha1", parser:take_while(occurrences:1.., set: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(name:"digit0", parser:take_while(occurrences:0.., set: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(name:"digit1", parser:take_while(occurrences:1.., set: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(name:"hex_digit0", parser:take_while(occurrences:0.., set: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(name:"hex_digit1", parser:take_while(occurrences:1.., set: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(name:"oct_digit0", parser:take_while(occurrences:0.., set: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(name:"oct_digit0", parser:take_while(occurrences:1.., set: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(name:"alphanumeric0", parser:take_while(occurrences:0.., set: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(name:"alphanumeric1", parser:take_while(occurrences:1.., set: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(name:"space0", parser:take_while(occurrences:0.., set:AsChar::is_space)).parse_next(input)
943}
944
945/// Recognizes zero 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(name:"space1", parser:take_while(occurrences:1.., set: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(name:"multispace0", parser:take_while(occurrences: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(name:"multispace1", parser:take_while(occurrences: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 traceimpl Parser(name:"dec_uint", parser:move |input: &mut Input| {
1134 altVerifyMap, …, …, …>, …, …, …, …, …>(((one_of(set:'1'..='9'), digit0).void(), one_of(set:'0').void()))
1135 .recognize()
1136 .verify_map(|s: <Input as Stream>::Slice| {
1137 let s: &[u8] = s.as_bstr();
1138 // SAFETY: Only 7-bit ASCII characters are parsed
1139 let s: &str = unsafe { crate::lib::std::str::from_utf8_unchecked(s) };
1140 Output::try_from_dec_uint(slice: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 traceimpl Parser(name:"dec_int", parser:move |input: &mut Input| {
1219 let sign: impl Parser, …> = opt(parser:dispatch! {any.map(AsChar::as_char);
1220 '+' => empty.value(true),
1221 '-' => empty.value(false),
1222 _ => fail,
1223 });
1224 altVerifyMap, …, …, …>, …, …, …, …, …>(((sign, one_of(set:'1'..='9'), digit0).void(), one_of(set:'0').void()))
1225 .recognize()
1226 .verify_map(|s: <Input as Stream>::Slice| {
1227 let s: &[u8] = s.as_bstr();
1228 // SAFETY: Only 7-bit ASCII characters are parsed
1229 let s: &str = unsafe { crate::lib::std::str::from_utf8_unchecked(s) };
1230 Output::try_from_dec_int(slice: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 traceimpl Parser(name:"float", parser:move |input: &mut Input| {
1494 let s: ::Slice = recognize_float_or_exceptions(input)?;
1495 s.parse_slice()
1496 .ok_or_else(|| ErrMode::from_error_kind(input, kind:ErrorKind::Verify))
1497 })
1498 .parse_next(input)
1499}
1500
1501#[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
1502fn recognize_float_or_exceptions<I, E: ParserError<I>>(
1503 input: &mut I,
1504) -> PResult<<I as Stream>::Slice, E>
1505where
1506 I: StreamIsPartial,
1507 I: Stream,
1508 I: Compare<Caseless<&'static str>>,
1509 I: Compare<char>,
1510 <I as Stream>::Token: AsChar + Clone,
1511 <I as Stream>::IterOffsets: Clone,
1512 I: AsBStr,
1513{
1514 altimpl Parser::Slice, …>((
1515 recognize_float,
1516 crate::token::literal(Caseless("nan")),
1517 (
1518 opt(parser:one_of(['+', '-'])),
1519 crate::token::literal(Caseless("infinity")),
1520 )
1521 .recognize(),
1522 (
1523 opt(parser:one_of(['+', '-'])),
1524 crate::token::literal(Caseless("inf")),
1525 )
1526 .recognize(),
1527 ))
1528 .parse_next(input)
1529}
1530
1531#[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
1532fn recognize_float<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
1533where
1534 I: StreamIsPartial,
1535 I: Stream,
1536 I: Compare<char>,
1537 <I as Stream>::Token: AsChar + Clone,
1538 <I as Stream>::IterOffsets: Clone,
1539 I: AsBStr,
1540{
1541 (
1542 opt(parser:one_of(['+', '-'])),
1543 alt((
1544 (digit1, opt(('.', opt(parser:digit1)))).void(),
1545 ('.', digit1).void(),
1546 )),
1547 opt((one_of(['e', 'E']), opt(parser:one_of(['+', '-'])), cut_err(parser:digit1))),
1548 )
1549 .recognize()
1550 .parse_next(input)
1551}
1552
1553/// Recognize the input slice with escaped characters.
1554///
1555/// See also [`escaped_transform`]
1556///
1557/// # Example
1558///
1559/// ```rust
1560/// # use winnow::prelude::*;
1561/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed, IResult};
1562/// # use winnow::ascii::digit1;
1563/// # use winnow::prelude::*;
1564/// use winnow::ascii::take_escaped;
1565/// use winnow::token::one_of;
1566///
1567/// fn esc(s: &str) -> IResult<&str, &str> {
1568/// take_escaped(digit1, '\\', one_of(['"', 'n', '\\'])).parse_peek(s)
1569/// }
1570///
1571/// assert_eq!(esc("123;"), Ok((";", "123")));
1572/// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#)));
1573/// ```
1574///
1575/// ```rust
1576/// # use winnow::prelude::*;
1577/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed, IResult};
1578/// # use winnow::ascii::digit1;
1579/// # use winnow::prelude::*;
1580/// # use winnow::Partial;
1581/// use winnow::ascii::take_escaped;
1582/// use winnow::token::one_of;
1583///
1584/// fn esc(s: Partial<&str>) -> IResult<Partial<&str>, &str> {
1585/// take_escaped(digit1, '\\', one_of(['"', 'n', '\\'])).parse_peek(s)
1586/// }
1587///
1588/// assert_eq!(esc(Partial::new("123;")), Ok((Partial::new(";"), "123")));
1589/// assert_eq!(esc(Partial::new("12\\\"34;")), Ok((Partial::new(";"), "12\\\"34")));
1590/// ```
1591#[inline(always)]
1592pub fn take_escaped<'i, Input: 'i, Error, Normal, Escapable, NormalOutput, EscapableOutput>(
1593 mut normal: Normal,
1594 control_char: char,
1595 mut escapable: Escapable,
1596) -> impl Parser<Input, <Input as Stream>::Slice, Error>
1597where
1598 Input: StreamIsPartial + Stream + Compare<char>,
1599 Normal: Parser<Input, NormalOutput, Error>,
1600 Escapable: Parser<Input, EscapableOutput, Error>,
1601 Error: ParserError<Input>,
1602{
1603 trace(name:"take_escaped", parser:move |input: &mut Input| {
1604 if <Input as StreamIsPartial>::is_partial_supported() && input.is_partial() {
1605 streaming_escaped_internal(input, &mut normal, control_char, &mut escapable)
1606 } else {
1607 complete_escaped_internal(input, &mut normal, control_char, &mut escapable)
1608 }
1609 })
1610}
1611
1612/// Deprecated, replaced with [`take_escaped`]
1613#[deprecated(since = "0.6.4", note = "Replaced with `take_escaped`")]
1614#[inline(always)]
1615pub fn escaped<'i, Input: 'i, Error, Normal, Escapable, NormalOutput, EscapableOutput>(
1616 normal: Normal,
1617 control_char: char,
1618 escapable: Escapable,
1619) -> impl Parser<Input, <Input as Stream>::Slice, Error>
1620where
1621 Input: StreamIsPartial + Stream + Compare<char>,
1622 Normal: Parser<Input, NormalOutput, Error>,
1623 Escapable: Parser<Input, EscapableOutput, Error>,
1624 Error: ParserError<Input>,
1625{
1626 take_escaped(normal, control_char, escapable)
1627}
1628
1629fn streaming_escaped_internal<I, Error, F, G, O1, O2>(
1630 input: &mut I,
1631 normal: &mut F,
1632 control_char: char,
1633 escapable: &mut G,
1634) -> PResult<<I as Stream>::Slice, Error>
1635where
1636 I: StreamIsPartial,
1637 I: Stream,
1638 I: Compare<char>,
1639 F: Parser<I, O1, Error>,
1640 G: Parser<I, O2, Error>,
1641 Error: ParserError<I>,
1642{
1643 let start = input.checkpoint();
1644
1645 while input.eof_offset() > 0 {
1646 let current_len = input.eof_offset();
1647
1648 match opt(normal.by_ref()).parse_next(input)? {
1649 Some(_) => {
1650 if input.eof_offset() == current_len {
1651 let offset = input.offset_from(&start);
1652 input.reset(&start);
1653 return Ok(input.next_slice(offset));
1654 }
1655 }
1656 None => {
1657 if opt(control_char).parse_next(input)?.is_some() {
1658 let _ = escapable.parse_next(input)?;
1659 } else {
1660 let offset = input.offset_from(&start);
1661 input.reset(&start);
1662 return Ok(input.next_slice(offset));
1663 }
1664 }
1665 }
1666 }
1667
1668 Err(ErrMode::Incomplete(Needed::Unknown))
1669}
1670
1671fn complete_escaped_internal<'a, I: 'a, Error, F, G, O1, O2>(
1672 input: &mut I,
1673 normal: &mut F,
1674 control_char: char,
1675 escapable: &mut G,
1676) -> PResult<<I as Stream>::Slice, Error>
1677where
1678 I: StreamIsPartial,
1679 I: Stream,
1680 I: Compare<char>,
1681 F: Parser<I, O1, Error>,
1682 G: Parser<I, O2, Error>,
1683 Error: ParserError<I>,
1684{
1685 let start = input.checkpoint();
1686
1687 while input.eof_offset() > 0 {
1688 let current_len = input.eof_offset();
1689
1690 match opt(normal.by_ref()).parse_next(input)? {
1691 Some(_) => {
1692 if input.eof_offset() == current_len {
1693 let offset = input.offset_from(&start);
1694 input.reset(&start);
1695 return Ok(input.next_slice(offset));
1696 }
1697 }
1698 None => {
1699 if opt(control_char).parse_next(input)?.is_some() {
1700 let _ = escapable.parse_next(input)?;
1701 } else {
1702 let offset = input.offset_from(&start);
1703 input.reset(&start);
1704 return Ok(input.next_slice(offset));
1705 }
1706 }
1707 }
1708 }
1709
1710 input.reset(&start);
1711 Ok(input.finish())
1712}
1713
1714/// Parse escaped characters, unescaping them
1715///
1716/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character)
1717///
1718/// # Example
1719///
1720/// ```rust
1721/// # use winnow::prelude::*;
1722/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1723/// # use std::str::from_utf8;
1724/// use winnow::token::literal;
1725/// use winnow::ascii::escaped_transform;
1726/// use winnow::ascii::alpha1;
1727/// use winnow::combinator::alt;
1728///
1729/// fn parser<'s>(input: &mut &'s str) -> PResult<String, InputError<&'s str>> {
1730/// escaped_transform(
1731/// alpha1,
1732/// '\\',
1733/// alt((
1734/// "\\".value("\\"),
1735/// "\"".value("\""),
1736/// "n".value("\n"),
1737/// ))
1738/// ).parse_next(input)
1739/// }
1740///
1741/// assert_eq!(parser.parse_peek("ab\\\"cd"), Ok(("", String::from("ab\"cd"))));
1742/// assert_eq!(parser.parse_peek("ab\\ncd"), Ok(("", String::from("ab\ncd"))));
1743/// ```
1744///
1745/// ```
1746/// # use winnow::prelude::*;
1747/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
1748/// # use std::str::from_utf8;
1749/// # use winnow::Partial;
1750/// use winnow::token::literal;
1751/// use winnow::ascii::escaped_transform;
1752/// use winnow::ascii::alpha1;
1753/// use winnow::combinator::alt;
1754///
1755/// fn parser<'s>(input: &mut Partial<&'s str>) -> PResult<String, InputError<Partial<&'s str>>> {
1756/// escaped_transform(
1757/// alpha1,
1758/// '\\',
1759/// alt((
1760/// "\\".value("\\"),
1761/// "\"".value("\""),
1762/// "n".value("\n"),
1763/// ))
1764/// ).parse_next(input)
1765/// }
1766///
1767/// assert_eq!(parser.parse_peek(Partial::new("ab\\\"cd\"")), Ok((Partial::new("\""), String::from("ab\"cd"))));
1768/// ```
1769#[inline(always)]
1770pub fn escaped_transform<Input, Error, Normal, Escape, Output>(
1771 mut normal: Normal,
1772 control_char: char,
1773 mut escape: Escape,
1774) -> impl Parser<Input, Output, Error>
1775where
1776 Input: StreamIsPartial + Stream + Compare<char>,
1777 Output: crate::stream::Accumulate<<Input as Stream>::Slice>,
1778 Normal: Parser<Input, <Input as Stream>::Slice, Error>,
1779 Escape: Parser<Input, <Input as Stream>::Slice, Error>,
1780 Error: ParserError<Input>,
1781{
1782 trace(name:"escaped_transform", parser:move |input: &mut Input| {
1783 if <Input as StreamIsPartial>::is_partial_supported() && input.is_partial() {
1784 streaming_escaped_transform_internal(input, &mut normal, control_char, &mut escape)
1785 } else {
1786 complete_escaped_transform_internal(input, &mut normal, control_char, &mut escape)
1787 }
1788 })
1789}
1790
1791fn streaming_escaped_transform_internal<I, Error, F, G, Output>(
1792 input: &mut I,
1793 normal: &mut F,
1794 control_char: char,
1795 transform: &mut G,
1796) -> PResult<Output, Error>
1797where
1798 I: StreamIsPartial,
1799 I: Stream,
1800 I: Compare<char>,
1801 Output: crate::stream::Accumulate<<I as Stream>::Slice>,
1802 F: Parser<I, <I as Stream>::Slice, Error>,
1803 G: Parser<I, <I as Stream>::Slice, Error>,
1804 Error: ParserError<I>,
1805{
1806 let mut res: Output = Output::initial(capacity:Some(input.eof_offset()));
1807
1808 while input.eof_offset() > 0 {
1809 let current_len: usize = input.eof_offset();
1810 match opt(parser:normal.by_ref()).parse_next(input)? {
1811 Some(o: ::Slice) => {
1812 res.accumulate(acc:o);
1813 if input.eof_offset() == current_len {
1814 return Ok(res);
1815 }
1816 }
1817 None => {
1818 if opt(parser:control_char).parse_next(input)?.is_some() {
1819 let o: ::Slice = transform.parse_next(input)?;
1820 res.accumulate(acc:o);
1821 } else {
1822 return Ok(res);
1823 }
1824 }
1825 }
1826 }
1827 Err(ErrMode::Incomplete(Needed::Unknown))
1828}
1829
1830fn complete_escaped_transform_internal<I, Error, F, G, Output>(
1831 input: &mut I,
1832 normal: &mut F,
1833 control_char: char,
1834 transform: &mut G,
1835) -> PResult<Output, Error>
1836where
1837 I: StreamIsPartial,
1838 I: Stream,
1839 I: Compare<char>,
1840 Output: crate::stream::Accumulate<<I as Stream>::Slice>,
1841 F: Parser<I, <I as Stream>::Slice, Error>,
1842 G: Parser<I, <I as Stream>::Slice, Error>,
1843 Error: ParserError<I>,
1844{
1845 let mut res = Output::initial(Some(input.eof_offset()));
1846
1847 while input.eof_offset() > 0 {
1848 let current_len = input.eof_offset();
1849
1850 match opt(normal.by_ref()).parse_next(input)? {
1851 Some(o) => {
1852 res.accumulate(o);
1853 if input.eof_offset() == current_len {
1854 return Ok(res);
1855 }
1856 }
1857 None => {
1858 if opt(control_char).parse_next(input)?.is_some() {
1859 let o = transform.parse_next(input)?;
1860 res.accumulate(o);
1861 } else {
1862 return Ok(res);
1863 }
1864 }
1865 }
1866 }
1867 Ok(res)
1868}
1869
1870mod sealed {
1871 pub struct SealedMarker;
1872}
1873