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