1 | //! Character specific parsers and combinators |
2 | //! |
3 | //! Functions recognizing specific characters |
4 | |
5 | #[cfg (test)] |
6 | mod tests; |
7 | |
8 | use crate::lib::std::ops::{Add, Shl}; |
9 | |
10 | use crate::combinator::alt; |
11 | use crate::combinator::cut_err; |
12 | use crate::combinator::dispatch; |
13 | use crate::combinator::empty; |
14 | use crate::combinator::fail; |
15 | use crate::combinator::opt; |
16 | use crate::combinator::trace; |
17 | use crate::error::ParserError; |
18 | use crate::error::{ErrMode, ErrorKind, Needed}; |
19 | use crate::stream::FindSlice; |
20 | use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial}; |
21 | use crate::stream::{Compare, CompareResult}; |
22 | use crate::token::any; |
23 | use crate::token::one_of; |
24 | use crate::token::take_until; |
25 | use crate::token::take_while; |
26 | use crate::PResult; |
27 | use crate::Parser; |
28 | |
29 | /// Mark a value as case-insensitive for ASCII characters |
30 | /// |
31 | /// # Example |
32 | /// ```rust |
33 | /// # use winnow::prelude::*; |
34 | /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}}; |
35 | /// # use winnow::ascii::Caseless; |
36 | /// |
37 | /// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> { |
38 | /// Caseless("hello" ).parse_next(s) |
39 | /// } |
40 | /// |
41 | /// assert_eq!(parser.parse_peek("Hello, World!" ), Ok((", World!" , "Hello" ))); |
42 | /// assert_eq!(parser.parse_peek("hello, World!" ), Ok((", World!" , "hello" ))); |
43 | /// assert_eq!(parser.parse_peek("HeLlo, World!" ), Ok((", World!" , "HeLlo" ))); |
44 | /// assert_eq!(parser.parse_peek("Some" ), Err(ErrMode::Backtrack(InputError::new("Some" , ErrorKind::Tag)))); |
45 | /// assert_eq!(parser.parse_peek("" ), Err(ErrMode::Backtrack(InputError::new("" , ErrorKind::Tag)))); |
46 | /// ``` |
47 | #[derive (Copy, Clone, Debug)] |
48 | pub struct Caseless<T>(pub T); |
49 | |
50 | impl Caseless<&str> { |
51 | /// Get the byte-representation of this case-insensitive value |
52 | #[inline (always)] |
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)] |
100 | pub fn crlf<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
101 | where |
102 | Input: StreamIsPartial + Stream + Compare<&'static str>, |
103 | Error: ParserError<Input>, |
104 | { |
105 | trace(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)] |
155 | pub fn till_line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
156 | where |
157 | Input: StreamIsPartial + Stream + Compare<&'static str> + FindSlice<(char, char)>, |
158 | <Input as Stream>::Token: AsChar + Clone, |
159 | Error: ParserError<Input>, |
160 | { |
161 | 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 | |
171 | fn till_line_ending_<I, E: ParserError<I>, const PARTIAL: bool>( |
172 | input: &mut I, |
173 | ) -> PResult<<I as Stream>::Slice, E> |
174 | where |
175 | I: StreamIsPartial, |
176 | I: Stream, |
177 | I: Compare<&'static str>, |
178 | I: FindSlice<(char, char)>, |
179 | <I as Stream>::Token: AsChar + Clone, |
180 | { |
181 | let res: ::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)] |
246 | pub fn line_ending<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
247 | where |
248 | Input: StreamIsPartial + Stream + Compare<&'static str>, |
249 | Error: ParserError<Input>, |
250 | { |
251 | trace(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)] |
296 | pub fn newline<I, Error: ParserError<I>>(input: &mut I) -> PResult<char, Error> |
297 | where |
298 | I: StreamIsPartial, |
299 | I: Stream, |
300 | I: Compare<char>, |
301 | { |
302 | trace(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)] |
347 | pub fn tab<Input, Error>(input: &mut Input) -> PResult<char, Error> |
348 | where |
349 | Input: StreamIsPartial + Stream + Compare<char>, |
350 | Error: ParserError<Input>, |
351 | { |
352 | trace(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)] |
399 | pub fn alpha0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
400 | where |
401 | Input: StreamIsPartial + Stream, |
402 | <Input as Stream>::Token: AsChar, |
403 | Error: ParserError<Input>, |
404 | { |
405 | trace(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)] |
452 | pub fn alpha1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
453 | where |
454 | Input: StreamIsPartial + Stream, |
455 | <Input as Stream>::Token: AsChar, |
456 | Error: ParserError<Input>, |
457 | { |
458 | trace(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)] |
506 | pub fn digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
507 | where |
508 | Input: StreamIsPartial + Stream, |
509 | <Input as Stream>::Token: AsChar, |
510 | Error: ParserError<Input>, |
511 | { |
512 | trace(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)] |
576 | pub fn digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
577 | where |
578 | Input: StreamIsPartial + Stream, |
579 | <Input as Stream>::Token: AsChar, |
580 | Error: ParserError<Input>, |
581 | { |
582 | trace(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)] |
629 | pub fn hex_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
630 | where |
631 | Input: StreamIsPartial + Stream, |
632 | <Input as Stream>::Token: AsChar, |
633 | Error: ParserError<Input>, |
634 | { |
635 | trace(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)] |
683 | pub fn hex_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
684 | where |
685 | Input: StreamIsPartial + Stream, |
686 | <Input as Stream>::Token: AsChar, |
687 | Error: ParserError<Input>, |
688 | { |
689 | trace(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)] |
736 | pub fn oct_digit0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
737 | where |
738 | Input: StreamIsPartial, |
739 | Input: Stream, |
740 | <Input as Stream>::Token: AsChar, |
741 | Error: ParserError<Input>, |
742 | { |
743 | trace(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)] |
790 | pub fn oct_digit1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
791 | where |
792 | Input: StreamIsPartial + Stream, |
793 | <Input as Stream>::Token: AsChar, |
794 | Error: ParserError<Input>, |
795 | { |
796 | trace(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)] |
843 | pub fn alphanumeric0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
844 | where |
845 | Input: StreamIsPartial + Stream, |
846 | <Input as Stream>::Token: AsChar, |
847 | Error: ParserError<Input>, |
848 | { |
849 | trace(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)] |
896 | pub fn alphanumeric1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
897 | where |
898 | Input: StreamIsPartial + Stream, |
899 | <Input as Stream>::Token: AsChar, |
900 | Error: ParserError<Input>, |
901 | { |
902 | trace(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)] |
936 | pub fn space0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
937 | where |
938 | Input: StreamIsPartial + Stream, |
939 | <Input as Stream>::Token: AsChar, |
940 | Error: ParserError<Input>, |
941 | { |
942 | trace(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)] |
989 | pub fn space1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
990 | where |
991 | Input: StreamIsPartial + Stream, |
992 | <Input as Stream>::Token: AsChar, |
993 | Error: ParserError<Input>, |
994 | { |
995 | trace(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)] |
1042 | pub fn multispace0<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
1043 | where |
1044 | Input: StreamIsPartial + Stream, |
1045 | <Input as Stream>::Token: AsChar + Clone, |
1046 | Error: ParserError<Input>, |
1047 | { |
1048 | trace(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)] |
1095 | pub fn multispace1<Input, Error>(input: &mut Input) -> PResult<<Input as Stream>::Slice, Error> |
1096 | where |
1097 | Input: StreamIsPartial + Stream, |
1098 | <Input as Stream>::Token: AsChar + Clone, |
1099 | Error: ParserError<Input>, |
1100 | { |
1101 | trace(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" )] |
1125 | pub fn dec_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> |
1126 | where |
1127 | Input: StreamIsPartial + Stream, |
1128 | <Input as Stream>::Slice: AsBStr, |
1129 | <Input as Stream>::Token: AsChar + Clone, |
1130 | Output: Uint, |
1131 | Error: ParserError<Input>, |
1132 | { |
1133 | 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`] |
1148 | pub trait Uint: Sized { |
1149 | #[doc (hidden)] |
1150 | fn try_from_dec_uint(slice: &str) -> Option<Self>; |
1151 | } |
1152 | |
1153 | impl Uint for u8 { |
1154 | fn try_from_dec_uint(slice: &str) -> Option<Self> { |
1155 | slice.parse().ok() |
1156 | } |
1157 | } |
1158 | |
1159 | impl Uint for u16 { |
1160 | fn try_from_dec_uint(slice: &str) -> Option<Self> { |
1161 | slice.parse().ok() |
1162 | } |
1163 | } |
1164 | |
1165 | impl Uint for u32 { |
1166 | fn try_from_dec_uint(slice: &str) -> Option<Self> { |
1167 | slice.parse().ok() |
1168 | } |
1169 | } |
1170 | |
1171 | impl Uint for u64 { |
1172 | fn try_from_dec_uint(slice: &str) -> Option<Self> { |
1173 | slice.parse().ok() |
1174 | } |
1175 | } |
1176 | |
1177 | impl Uint for u128 { |
1178 | fn try_from_dec_uint(slice: &str) -> Option<Self> { |
1179 | slice.parse().ok() |
1180 | } |
1181 | } |
1182 | |
1183 | impl 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" )] |
1210 | pub fn dec_int<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> |
1211 | where |
1212 | Input: StreamIsPartial + Stream, |
1213 | <Input as Stream>::Slice: AsBStr, |
1214 | <Input as Stream>::Token: AsChar + Clone, |
1215 | Output: Int, |
1216 | Error: ParserError<Input>, |
1217 | { |
1218 | 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`] |
1238 | pub trait Int: Sized { |
1239 | #[doc (hidden)] |
1240 | fn try_from_dec_int(slice: &str) -> Option<Self>; |
1241 | } |
1242 | |
1243 | impl Int for i8 { |
1244 | fn try_from_dec_int(slice: &str) -> Option<Self> { |
1245 | slice.parse().ok() |
1246 | } |
1247 | } |
1248 | |
1249 | impl Int for i16 { |
1250 | fn try_from_dec_int(slice: &str) -> Option<Self> { |
1251 | slice.parse().ok() |
1252 | } |
1253 | } |
1254 | |
1255 | impl Int for i32 { |
1256 | fn try_from_dec_int(slice: &str) -> Option<Self> { |
1257 | slice.parse().ok() |
1258 | } |
1259 | } |
1260 | |
1261 | impl Int for i64 { |
1262 | fn try_from_dec_int(slice: &str) -> Option<Self> { |
1263 | slice.parse().ok() |
1264 | } |
1265 | } |
1266 | |
1267 | impl Int for i128 { |
1268 | fn try_from_dec_int(slice: &str) -> Option<Self> { |
1269 | slice.parse().ok() |
1270 | } |
1271 | } |
1272 | |
1273 | impl 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 ] |
1329 | pub fn hex_uint<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> |
1330 | where |
1331 | Input: StreamIsPartial + Stream, |
1332 | <Input as Stream>::Token: AsChar, |
1333 | <Input as Stream>::Slice: AsBStr, |
1334 | Output: HexUint, |
1335 | Error: ParserError<Input>, |
1336 | { |
1337 | trace("hex_uint" , move |input: &mut Input| { |
1338 | let invalid_offset = input |
1339 | .offset_for(|c| { |
1340 | let c = c.as_char(); |
1341 | !"0123456789abcdefABCDEF" .contains(c) |
1342 | }) |
1343 | .unwrap_or_else(|| input.eof_offset()); |
1344 | let max_nibbles = Output::max_nibbles(sealed::SealedMarker); |
1345 | let max_offset = input.offset_at(max_nibbles); |
1346 | let offset = match max_offset { |
1347 | Ok(max_offset) => { |
1348 | if max_offset < invalid_offset { |
1349 | // Overflow |
1350 | return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)); |
1351 | } else { |
1352 | invalid_offset |
1353 | } |
1354 | } |
1355 | Err(_) => { |
1356 | if <Input as StreamIsPartial>::is_partial_supported() |
1357 | && input.is_partial() |
1358 | && invalid_offset == input.eof_offset() |
1359 | { |
1360 | // Only the next byte is guaranteed required |
1361 | return Err(ErrMode::Incomplete(Needed::new(1))); |
1362 | } else { |
1363 | invalid_offset |
1364 | } |
1365 | } |
1366 | }; |
1367 | if offset == 0 { |
1368 | // Must be at least one digit |
1369 | return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); |
1370 | } |
1371 | let parsed = input.next_slice(offset); |
1372 | |
1373 | let mut res = Output::default(); |
1374 | for c in parsed.as_bstr() { |
1375 | let nibble = *c as char; |
1376 | let nibble = nibble.to_digit(16).unwrap_or(0) as u8; |
1377 | let nibble = Output::from(nibble); |
1378 | res = (res << Output::from(4)) + nibble; |
1379 | } |
1380 | |
1381 | Ok(res) |
1382 | }) |
1383 | .parse_next(input) |
1384 | } |
1385 | |
1386 | /// Metadata for parsing hex numbers, see [`hex_uint`] |
1387 | pub trait HexUint: |
1388 | Default + Shl<Self, Output = Self> + Add<Self, Output = Self> + From<u8> |
1389 | { |
1390 | #[doc (hidden)] |
1391 | fn max_nibbles(_: sealed::SealedMarker) -> usize; |
1392 | } |
1393 | |
1394 | impl HexUint for u8 { |
1395 | #[inline (always)] |
1396 | fn max_nibbles(_: sealed::SealedMarker) -> usize { |
1397 | 2 |
1398 | } |
1399 | } |
1400 | |
1401 | impl HexUint for u16 { |
1402 | #[inline (always)] |
1403 | fn max_nibbles(_: sealed::SealedMarker) -> usize { |
1404 | 4 |
1405 | } |
1406 | } |
1407 | |
1408 | impl HexUint for u32 { |
1409 | #[inline (always)] |
1410 | fn max_nibbles(_: sealed::SealedMarker) -> usize { |
1411 | 8 |
1412 | } |
1413 | } |
1414 | |
1415 | impl HexUint for u64 { |
1416 | #[inline (always)] |
1417 | fn max_nibbles(_: sealed::SealedMarker) -> usize { |
1418 | 16 |
1419 | } |
1420 | } |
1421 | |
1422 | impl 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 |
1485 | pub fn float<Input, Output, Error>(input: &mut Input) -> PResult<Output, Error> |
1486 | where |
1487 | Input: StreamIsPartial + Stream + Compare<Caseless<&'static str>> + Compare<char> + AsBStr, |
1488 | <Input as Stream>::Slice: ParseSlice<Output>, |
1489 | <Input as Stream>::Token: AsChar + Clone, |
1490 | <Input as Stream>::IterOffsets: Clone, |
1491 | Error: ParserError<Input>, |
1492 | { |
1493 | 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 |
1502 | fn recognize_float_or_exceptions<I, E: ParserError<I>>( |
1503 | input: &mut I, |
1504 | ) -> PResult<<I as Stream>::Slice, E> |
1505 | where |
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 |
1532 | fn recognize_float<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E> |
1533 | where |
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)] |
1592 | pub 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> |
1597 | where |
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)] |
1615 | pub 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> |
1620 | where |
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 | |
1629 | fn 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> |
1635 | where |
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 | |
1671 | fn 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> |
1677 | where |
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)] |
1770 | pub 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> |
1775 | where |
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 | |
1791 | fn 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> |
1797 | where |
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 | |
1830 | fn 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> |
1836 | where |
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 | |
1870 | mod sealed { |
1871 | pub struct SealedMarker; |
1872 | } |
1873 | |