/rust/registry/src/index.crates.io-1949cf8c6b5b557f/winnow-0.7.6/src/token/mod.rs
Line | Count | Source |
1 | | //! Parsers extracting tokens from the stream |
2 | | |
3 | | #[cfg(test)] |
4 | | mod tests; |
5 | | |
6 | | use crate::combinator::trace; |
7 | | use crate::combinator::DisplayDebug; |
8 | | use crate::error::Needed; |
9 | | use crate::error::ParserError; |
10 | | use crate::lib::std::result::Result::Ok; |
11 | | use crate::stream::Range; |
12 | | use crate::stream::{Compare, CompareResult, ContainsToken, FindSlice, Stream}; |
13 | | use crate::stream::{StreamIsPartial, ToUsize}; |
14 | | use crate::Parser; |
15 | | use crate::Result; |
16 | | |
17 | | /// Matches one token |
18 | | /// |
19 | | /// *Complete version*: Will return an error if there's not enough input data. |
20 | | /// |
21 | | /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. |
22 | | /// |
23 | | /// # Effective Signature |
24 | | /// |
25 | | /// Assuming you are parsing a `&str` [Stream]: |
26 | | /// ```rust |
27 | | /// # use winnow::prelude::*;; |
28 | | /// pub fn any(input: &mut &str) -> ModalResult<char> |
29 | | /// # { |
30 | | /// # winnow::token::any.parse_next(input) |
31 | | /// # } |
32 | | /// ``` |
33 | | /// |
34 | | /// # Example |
35 | | /// |
36 | | /// ```rust |
37 | | /// # use winnow::{token::any, error::ErrMode, error::ContextError}; |
38 | | /// # use winnow::prelude::*; |
39 | | /// fn parser(input: &mut &str) -> ModalResult<char> { |
40 | | /// any.parse_next(input) |
41 | | /// } |
42 | | /// |
43 | | /// assert_eq!(parser.parse_peek("abc"), Ok(("bc",'a'))); |
44 | | /// assert!(parser.parse_peek("").is_err()); |
45 | | /// ``` |
46 | | /// |
47 | | /// ```rust |
48 | | /// # use winnow::{token::any, error::ErrMode, error::ContextError, error::Needed}; |
49 | | /// # use winnow::prelude::*; |
50 | | /// # use winnow::Partial; |
51 | | /// assert_eq!(any::<_, ErrMode<ContextError>>.parse_peek(Partial::new("abc")), Ok((Partial::new("bc"),'a'))); |
52 | | /// assert_eq!(any::<_, ErrMode<ContextError>>.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
53 | | /// ``` |
54 | | #[inline(always)] |
55 | | #[doc(alias = "token")] |
56 | 0 | pub fn any<Input, Error>(input: &mut Input) -> Result<<Input as Stream>::Token, Error> |
57 | 0 | where |
58 | 0 | Input: StreamIsPartial + Stream, |
59 | 0 | Error: ParserError<Input>, |
60 | | { |
61 | 0 | trace("any", move |input: &mut Input| { |
62 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
63 | 0 | any_::<_, _, true>(input) |
64 | | } else { |
65 | 0 | any_::<_, _, false>(input) |
66 | | } |
67 | 0 | }) Unexecuted instantiation: winnow::token::any::<&str, winnow::error::ErrMode<winnow::error::ContextError>>::{closure#0}Unexecuted instantiation: winnow::token::any::<_, _>::{closure#0} |
68 | 0 | .parse_next(input) |
69 | 0 | } Unexecuted instantiation: winnow::token::any::<&str, winnow::error::ErrMode<winnow::error::ContextError>> Unexecuted instantiation: winnow::token::any::<_, _> |
70 | | |
71 | 0 | fn any_<I, E: ParserError<I>, const PARTIAL: bool>(input: &mut I) -> Result<<I as Stream>::Token, E> |
72 | 0 | where |
73 | 0 | I: StreamIsPartial, |
74 | 0 | I: Stream, |
75 | | { |
76 | 0 | input.next_token().ok_or_else(|| { |
77 | 0 | if PARTIAL && input.is_partial() { |
78 | 0 | ParserError::incomplete(input, Needed::new(1)) |
79 | | } else { |
80 | 0 | ParserError::from_input(input) |
81 | | } |
82 | 0 | }) Unexecuted instantiation: winnow::token::any_::<&str, winnow::error::ErrMode<winnow::error::ContextError>, false>::{closure#0}Unexecuted instantiation: winnow::token::any_::<&str, winnow::error::ErrMode<winnow::error::ContextError>, true>::{closure#0}Unexecuted instantiation: winnow::token::any_::<_, _, _>::{closure#0} |
83 | 0 | } Unexecuted instantiation: winnow::token::any_::<&str, winnow::error::ErrMode<winnow::error::ContextError>, false> Unexecuted instantiation: winnow::token::any_::<&str, winnow::error::ErrMode<winnow::error::ContextError>, true> Unexecuted instantiation: winnow::token::any_::<_, _, _> |
84 | | |
85 | | /// Recognizes a literal |
86 | | /// |
87 | | /// The input data will be compared to the literal combinator's argument and will return the part of |
88 | | /// the input that matches the argument |
89 | | /// |
90 | | /// It will return `Err(ErrMode::Backtrack(_))` if the input doesn't match the literal |
91 | | /// |
92 | | /// <div class="warning"> |
93 | | /// |
94 | | /// **Note:** [`Parser`] is implemented for strings and byte strings as a convenience (complete |
95 | | /// only) |
96 | | /// |
97 | | /// </div> |
98 | | /// |
99 | | /// # Effective Signature |
100 | | /// |
101 | | /// Assuming you are parsing a `&str` [Stream]: |
102 | | /// ```rust |
103 | | /// # use winnow::prelude::*;; |
104 | | /// # use winnow::error::ContextError; |
105 | | /// pub fn literal(literal: &str) -> impl Parser<&str, &str, ContextError> |
106 | | /// # { |
107 | | /// # winnow::token::literal(literal) |
108 | | /// # } |
109 | | /// ``` |
110 | | /// |
111 | | /// # Example |
112 | | /// ```rust |
113 | | /// # use winnow::prelude::*; |
114 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
115 | | /// # |
116 | | /// fn parser<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
117 | | /// "Hello".parse_next(s) |
118 | | /// } |
119 | | /// |
120 | | /// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello"))); |
121 | | /// assert!(parser.parse_peek("Something").is_err()); |
122 | | /// assert!(parser.parse_peek("").is_err()); |
123 | | /// ``` |
124 | | /// |
125 | | /// ```rust |
126 | | /// # use winnow::prelude::*; |
127 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
128 | | /// # use winnow::Partial; |
129 | | /// |
130 | | /// fn parser<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
131 | | /// "Hello".parse_next(s) |
132 | | /// } |
133 | | /// |
134 | | /// assert_eq!(parser.parse_peek(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); |
135 | | /// assert!(parser.parse_peek(Partial::new("Something")).is_err()); |
136 | | /// assert!(parser.parse_peek(Partial::new("S")).is_err()); |
137 | | /// assert_eq!(parser.parse_peek(Partial::new("H")), Err(ErrMode::Incomplete(Needed::Unknown))); |
138 | | /// ``` |
139 | | /// |
140 | | /// ```rust |
141 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
142 | | /// # use winnow::prelude::*; |
143 | | /// use winnow::token::literal; |
144 | | /// use winnow::ascii::Caseless; |
145 | | /// |
146 | | /// fn parser<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
147 | | /// literal(Caseless("hello")).parse_next(s) |
148 | | /// } |
149 | | /// |
150 | | /// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello"))); |
151 | | /// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello"))); |
152 | | /// assert_eq!(parser.parse_peek("HeLlO, World!"), Ok((", World!", "HeLlO"))); |
153 | | /// assert!(parser.parse_peek("Something").is_err()); |
154 | | /// assert!(parser.parse_peek("").is_err()); |
155 | | /// ``` |
156 | | #[inline(always)] |
157 | | #[doc(alias = "tag")] |
158 | | #[doc(alias = "bytes")] |
159 | | #[doc(alias = "just")] |
160 | 0 | pub fn literal<Literal, Input, Error>( |
161 | 0 | literal: Literal, |
162 | 0 | ) -> impl Parser<Input, <Input as Stream>::Slice, Error> |
163 | 0 | where |
164 | 0 | Input: StreamIsPartial + Stream + Compare<Literal>, |
165 | 0 | Literal: Clone + crate::lib::std::fmt::Debug, |
166 | 0 | Error: ParserError<Input>, |
167 | | { |
168 | 0 | trace(DisplayDebug(literal.clone()), move |i: &mut Input| { |
169 | 0 | let t = literal.clone(); |
170 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
171 | 0 | literal_::<_, _, _, true>(i, t) |
172 | | } else { |
173 | 0 | literal_::<_, _, _, false>(i, t) |
174 | | } |
175 | 0 | }) Unexecuted instantiation: winnow::token::literal::<char, &str, winnow::error::ErrMode<winnow::error::ContextError>>::{closure#0}Unexecuted instantiation: winnow::token::literal::<_, _, _>::{closure#0} |
176 | 0 | } Unexecuted instantiation: winnow::token::literal::<char, &str, winnow::error::ErrMode<winnow::error::ContextError>> Unexecuted instantiation: winnow::token::literal::<_, _, _> |
177 | | |
178 | 0 | fn literal_<T, I, Error: ParserError<I>, const PARTIAL: bool>( |
179 | 0 | i: &mut I, |
180 | 0 | t: T, |
181 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
182 | 0 | where |
183 | 0 | I: StreamIsPartial, |
184 | 0 | I: Stream + Compare<T>, |
185 | 0 | T: crate::lib::std::fmt::Debug, |
186 | | { |
187 | 0 | match i.compare(t) { |
188 | 0 | CompareResult::Ok(len) => Ok(i.next_slice(len)), |
189 | 0 | CompareResult::Incomplete if PARTIAL && i.is_partial() => { |
190 | 0 | Err(ParserError::incomplete(i, Needed::Unknown)) |
191 | | } |
192 | 0 | CompareResult::Incomplete | CompareResult::Error => Err(ParserError::from_input(i)), |
193 | | } |
194 | 0 | } Unexecuted instantiation: winnow::token::literal_::<char, &str, winnow::error::ErrMode<winnow::error::ContextError>, false> Unexecuted instantiation: winnow::token::literal_::<char, &str, winnow::error::ErrMode<winnow::error::ContextError>, true> Unexecuted instantiation: winnow::token::literal_::<_, _, _, _> |
195 | | |
196 | | /// Recognize a token that matches a [set of tokens][ContainsToken] |
197 | | /// |
198 | | /// <div class="warning"> |
199 | | /// |
200 | | /// **Note:** [`Parser`] is implemented as a convenience (complete |
201 | | /// only) for |
202 | | /// - `u8` |
203 | | /// - `char` |
204 | | /// |
205 | | /// </div> |
206 | | /// |
207 | | /// *Complete version*: Will return an error if there's not enough input data. |
208 | | /// |
209 | | /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. |
210 | | /// |
211 | | /// # Effective Signature |
212 | | /// |
213 | | /// Assuming you are parsing a `&str` [Stream]: |
214 | | /// ```rust |
215 | | /// # use winnow::prelude::*;; |
216 | | /// # use winnow::stream::ContainsToken; |
217 | | /// # use winnow::error::ContextError; |
218 | | /// pub fn one_of<'i>(set: impl ContainsToken<char>) -> impl Parser<&'i str, char, ContextError> |
219 | | /// # { |
220 | | /// # winnow::token::one_of(set) |
221 | | /// # } |
222 | | /// ``` |
223 | | /// |
224 | | /// # Example |
225 | | /// |
226 | | /// ```rust |
227 | | /// # use winnow::prelude::*; |
228 | | /// # use winnow::{error::ErrMode, error::ContextError}; |
229 | | /// # use winnow::token::one_of; |
230 | | /// assert_eq!(one_of::<_, _, ContextError>(['a', 'b', 'c']).parse_peek("b"), Ok(("", 'b'))); |
231 | | /// assert!(one_of::<_, _, ContextError>('a').parse_peek("bc").is_err()); |
232 | | /// assert!(one_of::<_, _, ContextError>('a').parse_peek("").is_err()); |
233 | | /// |
234 | | /// fn parser_fn(i: &mut &str) -> ModalResult<char> { |
235 | | /// one_of(|c| c == 'a' || c == 'b').parse_next(i) |
236 | | /// } |
237 | | /// assert_eq!(parser_fn.parse_peek("abc"), Ok(("bc", 'a'))); |
238 | | /// assert!(parser_fn.parse_peek("cd").is_err()); |
239 | | /// assert!(parser_fn.parse_peek("").is_err()); |
240 | | /// ``` |
241 | | /// |
242 | | /// ```rust |
243 | | /// # use winnow::prelude::*; |
244 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
245 | | /// # use winnow::Partial; |
246 | | /// # use winnow::token::one_of; |
247 | | /// assert_eq!(one_of::<_, _, ErrMode<ContextError>>(['a', 'b', 'c']).parse_peek(Partial::new("b")), Ok((Partial::new(""), 'b'))); |
248 | | /// assert!(one_of::<_, _, ErrMode<ContextError>>('a').parse_peek(Partial::new("bc")).is_err()); |
249 | | /// assert_eq!(one_of::<_, _, ErrMode<ContextError>>('a').parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
250 | | /// |
251 | | /// fn parser_fn(i: &mut Partial<&str>) -> ModalResult<char> { |
252 | | /// one_of(|c| c == 'a' || c == 'b').parse_next(i) |
253 | | /// } |
254 | | /// assert_eq!(parser_fn.parse_peek(Partial::new("abc")), Ok((Partial::new("bc"), 'a'))); |
255 | | /// assert!(parser_fn.parse_peek(Partial::new("cd")).is_err()); |
256 | | /// assert_eq!(parser_fn.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
257 | | /// ``` |
258 | | #[inline(always)] |
259 | | #[doc(alias = "char")] |
260 | | #[doc(alias = "token")] |
261 | | #[doc(alias = "satisfy")] |
262 | 0 | pub fn one_of<Input, Set, Error>(set: Set) -> impl Parser<Input, <Input as Stream>::Token, Error> |
263 | 0 | where |
264 | 0 | Input: StreamIsPartial + Stream, |
265 | 0 | <Input as Stream>::Token: Clone, |
266 | 0 | Set: ContainsToken<<Input as Stream>::Token>, |
267 | 0 | Error: ParserError<Input>, |
268 | | { |
269 | 0 | trace( |
270 | | "one_of", |
271 | 0 | any.verify(move |t: &<Input as Stream>::Token| set.contains_token(t.clone())), Unexecuted instantiation: winnow::token::one_of::<&str, <duration_str::CondUnit>::contain, winnow::error::ErrMode<winnow::error::ContextError>>::{closure#0}Unexecuted instantiation: winnow::token::one_of::<_, _, _>::{closure#0} |
272 | | ) |
273 | 0 | } Unexecuted instantiation: winnow::token::one_of::<&str, <duration_str::CondUnit>::contain, winnow::error::ErrMode<winnow::error::ContextError>> Unexecuted instantiation: winnow::token::one_of::<_, _, _> |
274 | | |
275 | | /// Recognize a token that does not match a [set of tokens][ContainsToken] |
276 | | /// |
277 | | /// *Complete version*: Will return an error if there's not enough input data. |
278 | | /// |
279 | | /// *[Partial version][crate::_topic::partial]*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. |
280 | | /// |
281 | | /// # Effective Signature |
282 | | /// |
283 | | /// Assuming you are parsing a `&str` [Stream]: |
284 | | /// ```rust |
285 | | /// # use winnow::prelude::*;; |
286 | | /// # use winnow::stream::ContainsToken; |
287 | | /// # use winnow::error::ContextError; |
288 | | /// pub fn none_of<'i>(set: impl ContainsToken<char>) -> impl Parser<&'i str, char, ContextError> |
289 | | /// # { |
290 | | /// # winnow::token::none_of(set) |
291 | | /// # } |
292 | | /// ``` |
293 | | /// |
294 | | /// # Example |
295 | | /// |
296 | | /// ```rust |
297 | | /// # use winnow::{error::ErrMode, error::ContextError}; |
298 | | /// # use winnow::prelude::*; |
299 | | /// # use winnow::token::none_of; |
300 | | /// assert_eq!(none_of::<_, _, ContextError>(['a', 'b', 'c']).parse_peek("z"), Ok(("", 'z'))); |
301 | | /// assert!(none_of::<_, _, ContextError>(['a', 'b']).parse_peek("a").is_err()); |
302 | | /// assert!(none_of::<_, _, ContextError>('a').parse_peek("").is_err()); |
303 | | /// ``` |
304 | | /// |
305 | | /// ```rust |
306 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
307 | | /// # use winnow::prelude::*; |
308 | | /// # use winnow::Partial; |
309 | | /// # use winnow::token::none_of; |
310 | | /// assert_eq!(none_of::<_, _, ErrMode<ContextError>>(['a', 'b', 'c']).parse_peek(Partial::new("z")), Ok((Partial::new(""), 'z'))); |
311 | | /// assert!(none_of::<_, _, ErrMode<ContextError>>(['a', 'b']).parse_peek(Partial::new("a")).is_err()); |
312 | | /// assert_eq!(none_of::<_, _, ErrMode<ContextError>>('a').parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
313 | | /// ``` |
314 | | #[inline(always)] |
315 | 0 | pub fn none_of<Input, Set, Error>(set: Set) -> impl Parser<Input, <Input as Stream>::Token, Error> |
316 | 0 | where |
317 | 0 | Input: StreamIsPartial + Stream, |
318 | 0 | <Input as Stream>::Token: Clone, |
319 | 0 | Set: ContainsToken<<Input as Stream>::Token>, |
320 | 0 | Error: ParserError<Input>, |
321 | | { |
322 | 0 | trace( |
323 | | "none_of", |
324 | 0 | any.verify(move |t: &<Input as Stream>::Token| !set.contains_token(t.clone())), |
325 | | ) |
326 | 0 | } |
327 | | |
328 | | /// Recognize the longest (m <= len <= n) input slice that matches a [set of tokens][ContainsToken] |
329 | | /// |
330 | | /// It will return an `ErrMode::Backtrack(_)` if the set of tokens wasn't met or is out |
331 | | /// of range (m <= len <= n). |
332 | | /// |
333 | | /// *[Partial version][crate::_topic::partial]* will return a `ErrMode::Incomplete(Needed::new(1))` if a member of the set of tokens reaches the end of the input or is too short. |
334 | | /// |
335 | | /// To take a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::take`]. |
336 | | /// |
337 | | /// # Effective Signature |
338 | | /// |
339 | | /// Assuming you are parsing a `&str` [Stream] with `0..` or `1..` [ranges][Range]: |
340 | | /// ```rust |
341 | | /// # use std::ops::RangeFrom; |
342 | | /// # use winnow::prelude::*; |
343 | | /// # use winnow::stream::ContainsToken; |
344 | | /// # use winnow::error::ContextError; |
345 | | /// pub fn take_while<'i>(occurrences: RangeFrom<usize>, set: impl ContainsToken<char>) -> impl Parser<&'i str, &'i str, ContextError> |
346 | | /// # { |
347 | | /// # winnow::token::take_while(occurrences, set) |
348 | | /// # } |
349 | | /// ``` |
350 | | /// |
351 | | /// # Example |
352 | | /// |
353 | | /// Zero or more tokens: |
354 | | /// ```rust |
355 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
356 | | /// # use winnow::prelude::*; |
357 | | /// use winnow::token::take_while; |
358 | | /// use winnow::stream::AsChar; |
359 | | /// |
360 | | /// fn alpha<'i>(s: &mut &'i [u8]) -> ModalResult<&'i [u8]> { |
361 | | /// take_while(0.., AsChar::is_alpha).parse_next(s) |
362 | | /// } |
363 | | /// |
364 | | /// assert_eq!(alpha.parse_peek(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
365 | | /// assert_eq!(alpha.parse_peek(b"12345"), Ok((&b"12345"[..], &b""[..]))); |
366 | | /// assert_eq!(alpha.parse_peek(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
367 | | /// assert_eq!(alpha.parse_peek(b""), Ok((&b""[..], &b""[..]))); |
368 | | /// ``` |
369 | | /// |
370 | | /// ```rust |
371 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
372 | | /// # use winnow::prelude::*; |
373 | | /// # use winnow::Partial; |
374 | | /// use winnow::token::take_while; |
375 | | /// use winnow::stream::AsChar; |
376 | | /// |
377 | | /// fn alpha<'i>(s: &mut Partial<&'i [u8]>) -> ModalResult<&'i [u8]> { |
378 | | /// take_while(0.., AsChar::is_alpha).parse_next(s) |
379 | | /// } |
380 | | /// |
381 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); |
382 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"12345")), Ok((Partial::new(&b"12345"[..]), &b""[..]))); |
383 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); |
384 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"")), Err(ErrMode::Incomplete(Needed::new(1)))); |
385 | | /// ``` |
386 | | /// |
387 | | /// One or more tokens: |
388 | | /// ```rust |
389 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
390 | | /// # use winnow::prelude::*; |
391 | | /// use winnow::token::take_while; |
392 | | /// use winnow::stream::AsChar; |
393 | | /// |
394 | | /// fn alpha<'i>(s: &mut &'i [u8]) -> ModalResult<&'i [u8]> { |
395 | | /// take_while(1.., AsChar::is_alpha).parse_next(s) |
396 | | /// } |
397 | | /// |
398 | | /// assert_eq!(alpha.parse_peek(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
399 | | /// assert_eq!(alpha.parse_peek(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
400 | | /// assert!(alpha.parse_peek(b"12345").is_err()); |
401 | | /// |
402 | | /// fn hex<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
403 | | /// take_while(1.., ('0'..='9', 'A'..='F')).parse_next(s) |
404 | | /// } |
405 | | /// |
406 | | /// assert_eq!(hex.parse_peek("123 and voila"), Ok((" and voila", "123"))); |
407 | | /// assert_eq!(hex.parse_peek("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); |
408 | | /// assert_eq!(hex.parse_peek("BADBABEsomething"), Ok(("something", "BADBABE"))); |
409 | | /// assert_eq!(hex.parse_peek("D15EA5E"), Ok(("", "D15EA5E"))); |
410 | | /// assert!(hex.parse_peek("").is_err()); |
411 | | /// ``` |
412 | | /// |
413 | | /// ```rust |
414 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
415 | | /// # use winnow::prelude::*; |
416 | | /// # use winnow::Partial; |
417 | | /// use winnow::token::take_while; |
418 | | /// use winnow::stream::AsChar; |
419 | | /// |
420 | | /// fn alpha<'i>(s: &mut Partial<&'i [u8]>) -> ModalResult<&'i [u8]> { |
421 | | /// take_while(1.., AsChar::is_alpha).parse_next(s) |
422 | | /// } |
423 | | /// |
424 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); |
425 | | /// assert_eq!(alpha.parse_peek(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); |
426 | | /// assert!(alpha.parse_peek(Partial::new(b"12345")).is_err()); |
427 | | /// |
428 | | /// fn hex<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
429 | | /// take_while(1.., ('0'..='9', 'A'..='F')).parse_next(s) |
430 | | /// } |
431 | | /// |
432 | | /// assert_eq!(hex.parse_peek(Partial::new("123 and voila")), Ok((Partial::new(" and voila"), "123"))); |
433 | | /// assert_eq!(hex.parse_peek(Partial::new("DEADBEEF and others")), Ok((Partial::new(" and others"), "DEADBEEF"))); |
434 | | /// assert_eq!(hex.parse_peek(Partial::new("BADBABEsomething")), Ok((Partial::new("something"), "BADBABE"))); |
435 | | /// assert_eq!(hex.parse_peek(Partial::new("D15EA5E")), Err(ErrMode::Incomplete(Needed::new(1)))); |
436 | | /// assert_eq!(hex.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
437 | | /// ``` |
438 | | /// |
439 | | /// Arbitrary amount of tokens: |
440 | | /// ```rust |
441 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
442 | | /// # use winnow::prelude::*; |
443 | | /// use winnow::token::take_while; |
444 | | /// use winnow::stream::AsChar; |
445 | | /// |
446 | | /// fn short_alpha<'i>(s: &mut &'i [u8]) -> ModalResult<&'i [u8]> { |
447 | | /// take_while(3..=6, AsChar::is_alpha).parse_next(s) |
448 | | /// } |
449 | | /// |
450 | | /// assert_eq!(short_alpha.parse_peek(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
451 | | /// assert_eq!(short_alpha.parse_peek(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); |
452 | | /// assert_eq!(short_alpha.parse_peek(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
453 | | /// assert!(short_alpha.parse_peek(b"ed").is_err()); |
454 | | /// assert!(short_alpha.parse_peek(b"12345").is_err()); |
455 | | /// ``` |
456 | | /// |
457 | | /// ```rust |
458 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
459 | | /// # use winnow::prelude::*; |
460 | | /// # use winnow::Partial; |
461 | | /// use winnow::token::take_while; |
462 | | /// use winnow::stream::AsChar; |
463 | | /// |
464 | | /// fn short_alpha<'i>(s: &mut Partial<&'i [u8]>) -> ModalResult<&'i [u8]> { |
465 | | /// take_while(3..=6, AsChar::is_alpha).parse_next(s) |
466 | | /// } |
467 | | /// |
468 | | /// assert_eq!(short_alpha.parse_peek(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); |
469 | | /// assert_eq!(short_alpha.parse_peek(Partial::new(b"lengthy")), Ok((Partial::new(&b"y"[..]), &b"length"[..]))); |
470 | | /// assert_eq!(short_alpha.parse_peek(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); |
471 | | /// assert_eq!(short_alpha.parse_peek(Partial::new(b"ed")), Err(ErrMode::Incomplete(Needed::new(1)))); |
472 | | /// assert!(short_alpha.parse_peek(Partial::new(b"12345")).is_err()); |
473 | | /// ``` |
474 | | #[inline(always)] |
475 | | #[doc(alias = "is_a")] |
476 | | #[doc(alias = "take_while0")] |
477 | | #[doc(alias = "take_while1")] |
478 | 0 | pub fn take_while<Set, Input, Error>( |
479 | 0 | occurrences: impl Into<Range>, |
480 | 0 | set: Set, |
481 | 0 | ) -> impl Parser<Input, <Input as Stream>::Slice, Error> |
482 | 0 | where |
483 | 0 | Input: StreamIsPartial + Stream, |
484 | 0 | Set: ContainsToken<<Input as Stream>::Token>, |
485 | 0 | Error: ParserError<Input>, |
486 | | { |
487 | | let Range { |
488 | 0 | start_inclusive, |
489 | 0 | end_inclusive, |
490 | 0 | } = occurrences.into(); |
491 | 0 | trace("take_while", move |i: &mut Input| { |
492 | 0 | match (start_inclusive, end_inclusive) { |
493 | | (0, None) => { |
494 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
495 | 0 | take_till0::<_, _, _, true>(i, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#0} |
496 | | } else { |
497 | 0 | take_till0::<_, _, _, false>(i, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#1} |
498 | | } |
499 | | } |
500 | | (1, None) => { |
501 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
502 | 0 | take_till1::<_, _, _, true>(i, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#2} |
503 | | } else { |
504 | 0 | take_till1::<_, _, _, false>(i, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#3} |
505 | | } |
506 | | } |
507 | 0 | (start, end) => { |
508 | 0 | let end = end.unwrap_or(usize::MAX); |
509 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
510 | 0 | take_till_m_n::<_, _, _, true>(i, start, end, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#4} |
511 | | } else { |
512 | 0 | take_till_m_n::<_, _, _, false>(i, start, end, |c| !set.contains_token(c)) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0}::{closure#5} |
513 | | } |
514 | | } |
515 | | } |
516 | 0 | }) Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}Unexecuted instantiation: winnow::token::take_while::<_, _, _, _>::{closure#0} |
517 | 0 | } Unexecuted instantiation: winnow::token::take_while::<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>> Unexecuted instantiation: winnow::token::take_while::<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>> Unexecuted instantiation: winnow::token::take_while::<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>Unexecuted instantiation: winnow::token::take_while::<_, _, _, _> |
518 | | |
519 | 0 | fn take_till0<P, I: StreamIsPartial + Stream, E: ParserError<I>, const PARTIAL: bool>( |
520 | 0 | input: &mut I, |
521 | 0 | predicate: P, |
522 | 0 | ) -> Result<<I as Stream>::Slice, E> |
523 | 0 | where |
524 | 0 | P: Fn(I::Token) -> bool, |
525 | | { |
526 | 0 | let offset = match input.offset_for(predicate) { |
527 | 0 | Some(offset) => offset, |
528 | 0 | None if PARTIAL && input.is_partial() => { |
529 | 0 | return Err(ParserError::incomplete(input, Needed::new(1))); |
530 | | } |
531 | 0 | None => input.eof_offset(), |
532 | | }; |
533 | 0 | Ok(input.next_slice(offset)) |
534 | 0 | } Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till0::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#1}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till0::<_, _, _, _> |
535 | | |
536 | 0 | fn take_till1<P, I: StreamIsPartial + Stream, E: ParserError<I>, const PARTIAL: bool>( |
537 | 0 | input: &mut I, |
538 | 0 | predicate: P, |
539 | 0 | ) -> Result<<I as Stream>::Slice, E> |
540 | 0 | where |
541 | 0 | P: Fn(I::Token) -> bool, |
542 | | { |
543 | 0 | let offset = match input.offset_for(predicate) { |
544 | 0 | Some(offset) => offset, |
545 | 0 | None if PARTIAL && input.is_partial() => { |
546 | 0 | return Err(ParserError::incomplete(input, Needed::new(1))); |
547 | | } |
548 | 0 | None => input.eof_offset(), |
549 | | }; |
550 | 0 | if offset == 0 { |
551 | 0 | Err(ParserError::from_input(input)) |
552 | | } else { |
553 | 0 | Ok(input.next_slice(offset)) |
554 | | } |
555 | 0 | } Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#2}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till1::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#3}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till1::<_, _, _, _> |
556 | | |
557 | 0 | fn take_till_m_n<P, I, Error: ParserError<I>, const PARTIAL: bool>( |
558 | 0 | input: &mut I, |
559 | 0 | m: usize, |
560 | 0 | n: usize, |
561 | 0 | predicate: P, |
562 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
563 | 0 | where |
564 | 0 | I: StreamIsPartial, |
565 | 0 | I: Stream, |
566 | 0 | P: Fn(I::Token) -> bool, |
567 | | { |
568 | 0 | if n < m { |
569 | 0 | return Err(ParserError::assert( |
570 | 0 | input, |
571 | 0 | "`occurrences` should be ascending, rather than descending", |
572 | 0 | )); |
573 | 0 | } |
574 | | |
575 | 0 | let mut final_count = 0; |
576 | 0 | for (processed, (offset, token)) in input.iter_offsets().enumerate() { |
577 | 0 | if predicate(token) { |
578 | 0 | if processed < m { |
579 | 0 | return Err(ParserError::from_input(input)); |
580 | | } else { |
581 | 0 | return Ok(input.next_slice(offset)); |
582 | | } |
583 | | } else { |
584 | 0 | if processed == n { |
585 | 0 | return Ok(input.next_slice(offset)); |
586 | 0 | } |
587 | 0 | final_count = processed + 1; |
588 | | } |
589 | | } |
590 | 0 | if PARTIAL && input.is_partial() { |
591 | 0 | if final_count == n { |
592 | 0 | Ok(input.finish()) |
593 | | } else { |
594 | 0 | let needed = if m > input.eof_offset() { |
595 | 0 | m - input.eof_offset() |
596 | | } else { |
597 | 0 | 1 |
598 | | }; |
599 | 0 | Err(ParserError::incomplete(input, Needed::new(needed))) |
600 | | } |
601 | | } else { |
602 | 0 | if m <= final_count { |
603 | 0 | Ok(input.finish()) |
604 | | } else { |
605 | 0 | Err(ParserError::from_input(input)) |
606 | | } |
607 | | } |
608 | 0 | } Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<duration_str::unit::unit_abbr1::{closure#0}, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<<char as winnow::stream::AsChar>::is_dec_digit, &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#4}, &str, winnow::error::ErrMode<winnow::error::ContextError>, true>Unexecuted instantiation: winnow::token::take_till_m_n::<winnow::token::take_while<(char, char, char, char), &str, winnow::error::ErrMode<winnow::error::ContextError>, core::ops::range::RangeFrom<usize>>::{closure#0}::{closure#5}, &str, winnow::error::ErrMode<winnow::error::ContextError>, false>Unexecuted instantiation: winnow::token::take_till_m_n::<_, _, _, _> |
609 | | |
610 | | /// Recognize the longest input slice (if any) till a member of a [set of tokens][ContainsToken] is found. |
611 | | /// |
612 | | /// It doesn't consume the terminating token from the set. |
613 | | /// |
614 | | /// *[Partial version][crate::_topic::partial]* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the |
615 | | /// end of input or if there was not match. |
616 | | /// |
617 | | /// See also |
618 | | /// - [`take_until`] for recognizing up-to a [`literal`] (w/ optional simd optimizations) |
619 | | /// - [`repeat_till`][crate::combinator::repeat_till] with [`Parser::take`] for taking tokens up to a [`Parser`] |
620 | | /// |
621 | | /// # Effective Signature |
622 | | /// |
623 | | /// Assuming you are parsing a `&str` [Stream] with `0..` or `1..` [ranges][Range]: |
624 | | /// ```rust |
625 | | /// # use std::ops::RangeFrom; |
626 | | /// # use winnow::prelude::*; |
627 | | /// # use winnow::stream::ContainsToken; |
628 | | /// # use winnow::error::ContextError; |
629 | | /// pub fn take_till<'i>(occurrences: RangeFrom<usize>, set: impl ContainsToken<char>) -> impl Parser<&'i str, &'i str, ContextError> |
630 | | /// # { |
631 | | /// # winnow::token::take_till(occurrences, set) |
632 | | /// # } |
633 | | /// ``` |
634 | | /// |
635 | | /// # Example |
636 | | /// |
637 | | /// ```rust |
638 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
639 | | /// # use winnow::prelude::*; |
640 | | /// use winnow::token::take_till; |
641 | | /// |
642 | | /// fn till_colon<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
643 | | /// take_till(0.., |c| c == ':').parse_next(s) |
644 | | /// } |
645 | | /// |
646 | | /// assert_eq!(till_colon.parse_peek("latin:123"), Ok((":123", "latin"))); |
647 | | /// assert_eq!(till_colon.parse_peek(":empty matched"), Ok((":empty matched", ""))); //allowed |
648 | | /// assert_eq!(till_colon.parse_peek("12345"), Ok(("", "12345"))); |
649 | | /// assert_eq!(till_colon.parse_peek(""), Ok(("", ""))); |
650 | | /// ``` |
651 | | /// |
652 | | /// ```rust |
653 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
654 | | /// # use winnow::prelude::*; |
655 | | /// # use winnow::Partial; |
656 | | /// use winnow::token::take_till; |
657 | | /// |
658 | | /// fn till_colon<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
659 | | /// take_till(0.., |c| c == ':').parse_next(s) |
660 | | /// } |
661 | | /// |
662 | | /// assert_eq!(till_colon.parse_peek(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); |
663 | | /// assert_eq!(till_colon.parse_peek(Partial::new(":empty matched")), Ok((Partial::new(":empty matched"), ""))); //allowed |
664 | | /// assert_eq!(till_colon.parse_peek(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); |
665 | | /// assert_eq!(till_colon.parse_peek(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); |
666 | | /// ``` |
667 | | #[inline(always)] |
668 | | #[doc(alias = "is_not")] |
669 | 0 | pub fn take_till<Set, Input, Error>( |
670 | 0 | occurrences: impl Into<Range>, |
671 | 0 | set: Set, |
672 | 0 | ) -> impl Parser<Input, <Input as Stream>::Slice, Error> |
673 | 0 | where |
674 | 0 | Input: StreamIsPartial + Stream, |
675 | 0 | Set: ContainsToken<<Input as Stream>::Token>, |
676 | 0 | Error: ParserError<Input>, |
677 | | { |
678 | | let Range { |
679 | 0 | start_inclusive, |
680 | 0 | end_inclusive, |
681 | 0 | } = occurrences.into(); |
682 | 0 | trace("take_till", move |i: &mut Input| { |
683 | 0 | match (start_inclusive, end_inclusive) { |
684 | | (0, None) => { |
685 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
686 | 0 | take_till0::<_, _, _, true>(i, |c| set.contains_token(c)) |
687 | | } else { |
688 | 0 | take_till0::<_, _, _, false>(i, |c| set.contains_token(c)) |
689 | | } |
690 | | } |
691 | | (1, None) => { |
692 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
693 | 0 | take_till1::<_, _, _, true>(i, |c| set.contains_token(c)) |
694 | | } else { |
695 | 0 | take_till1::<_, _, _, false>(i, |c| set.contains_token(c)) |
696 | | } |
697 | | } |
698 | 0 | (start, end) => { |
699 | 0 | let end = end.unwrap_or(usize::MAX); |
700 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
701 | 0 | take_till_m_n::<_, _, _, true>(i, start, end, |c| set.contains_token(c)) |
702 | | } else { |
703 | 0 | take_till_m_n::<_, _, _, false>(i, start, end, |c| set.contains_token(c)) |
704 | | } |
705 | | } |
706 | | } |
707 | 0 | }) |
708 | 0 | } |
709 | | |
710 | | /// Recognize an input slice containing the first N input elements (I[..N]). |
711 | | /// |
712 | | /// *Complete version*: It will return `Err(ErrMode::Backtrack(_))` if the input is shorter than the argument. |
713 | | /// |
714 | | /// *[Partial version][crate::_topic::partial]*: if the input has less than N elements, `take` will |
715 | | /// return a `ErrMode::Incomplete(Needed::new(M))` where M is the number of |
716 | | /// additional bytes the parser would need to succeed. |
717 | | /// It is well defined for `&[u8]` as the number of elements is the byte size, |
718 | | /// but for types like `&str`, we cannot know how many bytes correspond for |
719 | | /// the next few chars, so the result will be `ErrMode::Incomplete(Needed::Unknown)` |
720 | | /// |
721 | | /// # Effective Signature |
722 | | /// |
723 | | /// Assuming you are parsing a `&str` [Stream] with `0..` or `1..` ranges: |
724 | | /// ```rust |
725 | | /// # use std::ops::RangeFrom; |
726 | | /// # use winnow::prelude::*; |
727 | | /// # use winnow::stream::ContainsToken; |
728 | | /// # use winnow::error::ContextError; |
729 | | /// pub fn take<'i>(token_count: usize) -> impl Parser<&'i str, &'i str, ContextError> |
730 | | /// # { |
731 | | /// # winnow::token::take(token_count) |
732 | | /// # } |
733 | | /// ``` |
734 | | /// |
735 | | /// # Example |
736 | | /// |
737 | | /// ```rust |
738 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
739 | | /// # use winnow::prelude::*; |
740 | | /// use winnow::token::take; |
741 | | /// |
742 | | /// fn take6<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
743 | | /// take(6usize).parse_next(s) |
744 | | /// } |
745 | | /// |
746 | | /// assert_eq!(take6.parse_peek("1234567"), Ok(("7", "123456"))); |
747 | | /// assert_eq!(take6.parse_peek("things"), Ok(("", "things"))); |
748 | | /// assert!(take6.parse_peek("short").is_err()); |
749 | | /// assert!(take6.parse_peek("").is_err()); |
750 | | /// ``` |
751 | | /// |
752 | | /// The units that are taken will depend on the input type. For example, for a |
753 | | /// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will |
754 | | /// take that many `u8`'s: |
755 | | /// |
756 | | /// ```rust |
757 | | /// # use winnow::prelude::*; |
758 | | /// use winnow::error::ContextError; |
759 | | /// use winnow::token::take; |
760 | | /// |
761 | | /// assert_eq!(take::<_, _, ContextError>(1usize).parse_peek("💙"), Ok(("", "💙"))); |
762 | | /// assert_eq!(take::<_, _, ContextError>(1usize).parse_peek("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref()))); |
763 | | /// ``` |
764 | | /// |
765 | | /// ```rust |
766 | | /// # use winnow::prelude::*; |
767 | | /// # use winnow::error::{ErrMode, ContextError, Needed}; |
768 | | /// # use winnow::Partial; |
769 | | /// use winnow::token::take; |
770 | | /// |
771 | | /// fn take6<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
772 | | /// take(6usize).parse_next(s) |
773 | | /// } |
774 | | /// |
775 | | /// assert_eq!(take6.parse_peek(Partial::new("1234567")), Ok((Partial::new("7"), "123456"))); |
776 | | /// assert_eq!(take6.parse_peek(Partial::new("things")), Ok((Partial::new(""), "things"))); |
777 | | /// // `Unknown` as we don't know the number of bytes that `count` corresponds to |
778 | | /// assert_eq!(take6.parse_peek(Partial::new("short")), Err(ErrMode::Incomplete(Needed::Unknown))); |
779 | | /// ``` |
780 | | #[inline(always)] |
781 | 0 | pub fn take<UsizeLike, Input, Error>( |
782 | 0 | token_count: UsizeLike, |
783 | 0 | ) -> impl Parser<Input, <Input as Stream>::Slice, Error> |
784 | 0 | where |
785 | 0 | Input: StreamIsPartial + Stream, |
786 | 0 | UsizeLike: ToUsize, |
787 | 0 | Error: ParserError<Input>, |
788 | | { |
789 | 0 | let c = token_count.to_usize(); |
790 | 0 | trace("take", move |i: &mut Input| { |
791 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
792 | 0 | take_::<_, _, true>(i, c) |
793 | | } else { |
794 | 0 | take_::<_, _, false>(i, c) |
795 | | } |
796 | 0 | }) |
797 | 0 | } |
798 | | |
799 | 0 | fn take_<I, Error: ParserError<I>, const PARTIAL: bool>( |
800 | 0 | i: &mut I, |
801 | 0 | c: usize, |
802 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
803 | 0 | where |
804 | 0 | I: StreamIsPartial, |
805 | 0 | I: Stream, |
806 | | { |
807 | 0 | match i.offset_at(c) { |
808 | 0 | Ok(offset) => Ok(i.next_slice(offset)), |
809 | 0 | Err(e) if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, e)), |
810 | 0 | Err(_needed) => Err(ParserError::from_input(i)), |
811 | | } |
812 | 0 | } |
813 | | |
814 | | /// Recognize the input slice up to the first occurrence of a [literal]. |
815 | | /// |
816 | | /// Feature `simd` will enable the use of [`memchr`](https://docs.rs/memchr/latest/memchr/). |
817 | | /// |
818 | | /// It doesn't consume the literal. |
819 | | /// |
820 | | /// *Complete version*: It will return `Err(ErrMode::Backtrack(_))` |
821 | | /// if the literal wasn't met. |
822 | | /// |
823 | | /// *[Partial version][crate::_topic::partial]*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't |
824 | | /// contain the literal or if the input is smaller than the literal. |
825 | | /// |
826 | | /// See also |
827 | | /// - [`take_till`] for recognizing up-to a [set of tokens][ContainsToken] |
828 | | /// - [`repeat_till`][crate::combinator::repeat_till] with [`Parser::take`] for taking tokens up to a [`Parser`] |
829 | | /// |
830 | | /// # Effective Signature |
831 | | /// |
832 | | /// Assuming you are parsing a `&str` [Stream] with `0..` or `1..` [ranges][Range]: |
833 | | /// ```rust |
834 | | /// # use std::ops::RangeFrom; |
835 | | /// # use winnow::prelude::*;; |
836 | | /// # use winnow::error::ContextError; |
837 | | /// pub fn take_until(occurrences: RangeFrom<usize>, literal: &str) -> impl Parser<&str, &str, ContextError> |
838 | | /// # { |
839 | | /// # winnow::token::take_until(occurrences, literal) |
840 | | /// # } |
841 | | /// ``` |
842 | | /// |
843 | | /// # Example |
844 | | /// |
845 | | /// ```rust |
846 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
847 | | /// # use winnow::prelude::*; |
848 | | /// use winnow::token::take_until; |
849 | | /// |
850 | | /// fn until_eof<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
851 | | /// take_until(0.., "eof").parse_next(s) |
852 | | /// } |
853 | | /// |
854 | | /// assert_eq!(until_eof.parse_peek("hello, worldeof"), Ok(("eof", "hello, world"))); |
855 | | /// assert!(until_eof.parse_peek("hello, world").is_err()); |
856 | | /// assert!(until_eof.parse_peek("").is_err()); |
857 | | /// assert_eq!(until_eof.parse_peek("1eof2eof"), Ok(("eof2eof", "1"))); |
858 | | /// ``` |
859 | | /// |
860 | | /// ```rust |
861 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
862 | | /// # use winnow::prelude::*; |
863 | | /// # use winnow::Partial; |
864 | | /// use winnow::token::take_until; |
865 | | /// |
866 | | /// fn until_eof<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
867 | | /// take_until(0.., "eof").parse_next(s) |
868 | | /// } |
869 | | /// |
870 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); |
871 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); |
872 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); |
873 | | /// assert_eq!(until_eof.parse_peek(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); |
874 | | /// ``` |
875 | | /// |
876 | | /// ```rust |
877 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
878 | | /// # use winnow::prelude::*; |
879 | | /// use winnow::token::take_until; |
880 | | /// |
881 | | /// fn until_eof<'i>(s: &mut &'i str) -> ModalResult<&'i str> { |
882 | | /// take_until(1.., "eof").parse_next(s) |
883 | | /// } |
884 | | /// |
885 | | /// assert_eq!(until_eof.parse_peek("hello, worldeof"), Ok(("eof", "hello, world"))); |
886 | | /// assert!(until_eof.parse_peek("hello, world").is_err()); |
887 | | /// assert!(until_eof.parse_peek("").is_err()); |
888 | | /// assert_eq!(until_eof.parse_peek("1eof2eof"), Ok(("eof2eof", "1"))); |
889 | | /// assert!(until_eof.parse_peek("eof").is_err()); |
890 | | /// ``` |
891 | | /// |
892 | | /// ```rust |
893 | | /// # use winnow::{error::ErrMode, error::ContextError, error::Needed}; |
894 | | /// # use winnow::prelude::*; |
895 | | /// # use winnow::Partial; |
896 | | /// use winnow::token::take_until; |
897 | | /// |
898 | | /// fn until_eof<'i>(s: &mut Partial<&'i str>) -> ModalResult<&'i str> { |
899 | | /// take_until(1.., "eof").parse_next(s) |
900 | | /// } |
901 | | /// |
902 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); |
903 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); |
904 | | /// assert_eq!(until_eof.parse_peek(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); |
905 | | /// assert_eq!(until_eof.parse_peek(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); |
906 | | /// assert!(until_eof.parse_peek(Partial::new("eof")).is_err()); |
907 | | /// ``` |
908 | | #[inline(always)] |
909 | 0 | pub fn take_until<Literal, Input, Error>( |
910 | 0 | occurrences: impl Into<Range>, |
911 | 0 | literal: Literal, |
912 | 0 | ) -> impl Parser<Input, <Input as Stream>::Slice, Error> |
913 | 0 | where |
914 | 0 | Input: StreamIsPartial + Stream + FindSlice<Literal>, |
915 | 0 | Literal: Clone, |
916 | 0 | Error: ParserError<Input>, |
917 | | { |
918 | | let Range { |
919 | 0 | start_inclusive, |
920 | 0 | end_inclusive, |
921 | 0 | } = occurrences.into(); |
922 | 0 | trace("take_until", move |i: &mut Input| { |
923 | 0 | match (start_inclusive, end_inclusive) { |
924 | | (0, None) => { |
925 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
926 | 0 | take_until0_::<_, _, _, true>(i, literal.clone()) |
927 | | } else { |
928 | 0 | take_until0_::<_, _, _, false>(i, literal.clone()) |
929 | | } |
930 | | } |
931 | | (1, None) => { |
932 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
933 | 0 | take_until1_::<_, _, _, true>(i, literal.clone()) |
934 | | } else { |
935 | 0 | take_until1_::<_, _, _, false>(i, literal.clone()) |
936 | | } |
937 | | } |
938 | 0 | (start, end) => { |
939 | 0 | let end = end.unwrap_or(usize::MAX); |
940 | 0 | if <Input as StreamIsPartial>::is_partial_supported() { |
941 | 0 | take_until_m_n_::<_, _, _, true>(i, start, end, literal.clone()) |
942 | | } else { |
943 | 0 | take_until_m_n_::<_, _, _, false>(i, start, end, literal.clone()) |
944 | | } |
945 | | } |
946 | | } |
947 | 0 | }) |
948 | 0 | } |
949 | | |
950 | 0 | fn take_until0_<T, I, Error: ParserError<I>, const PARTIAL: bool>( |
951 | 0 | i: &mut I, |
952 | 0 | t: T, |
953 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
954 | 0 | where |
955 | 0 | I: StreamIsPartial, |
956 | 0 | I: Stream + FindSlice<T>, |
957 | | { |
958 | 0 | match i.find_slice(t) { |
959 | 0 | Some(range) => Ok(i.next_slice(range.start)), |
960 | 0 | None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)), |
961 | 0 | None => Err(ParserError::from_input(i)), |
962 | | } |
963 | 0 | } |
964 | | |
965 | 0 | fn take_until1_<T, I, Error: ParserError<I>, const PARTIAL: bool>( |
966 | 0 | i: &mut I, |
967 | 0 | t: T, |
968 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
969 | 0 | where |
970 | 0 | I: StreamIsPartial, |
971 | 0 | I: Stream + FindSlice<T>, |
972 | | { |
973 | 0 | match i.find_slice(t) { |
974 | 0 | None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)), |
975 | 0 | None => Err(ParserError::from_input(i)), |
976 | 0 | Some(range) => { |
977 | 0 | if range.start == 0 { |
978 | 0 | Err(ParserError::from_input(i)) |
979 | | } else { |
980 | 0 | Ok(i.next_slice(range.start)) |
981 | | } |
982 | | } |
983 | | } |
984 | 0 | } |
985 | | |
986 | 0 | fn take_until_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>( |
987 | 0 | i: &mut I, |
988 | 0 | start: usize, |
989 | 0 | end: usize, |
990 | 0 | t: T, |
991 | 0 | ) -> Result<<I as Stream>::Slice, Error> |
992 | 0 | where |
993 | 0 | I: StreamIsPartial, |
994 | 0 | I: Stream + FindSlice<T>, |
995 | | { |
996 | 0 | if end < start { |
997 | 0 | return Err(ParserError::assert( |
998 | 0 | i, |
999 | 0 | "`occurrences` should be ascending, rather than descending", |
1000 | 0 | )); |
1001 | 0 | } |
1002 | | |
1003 | 0 | match i.find_slice(t) { |
1004 | 0 | Some(range) => { |
1005 | 0 | let start_offset = i.offset_at(start); |
1006 | 0 | let end_offset = i.offset_at(end).unwrap_or_else(|_err| i.eof_offset()); |
1007 | 0 | if start_offset.map(|s| range.start < s).unwrap_or(true) { |
1008 | 0 | if PARTIAL && i.is_partial() { |
1009 | 0 | return Err(ParserError::incomplete(i, Needed::Unknown)); |
1010 | | } else { |
1011 | 0 | return Err(ParserError::from_input(i)); |
1012 | | } |
1013 | 0 | } |
1014 | 0 | if end_offset < range.start { |
1015 | 0 | return Err(ParserError::from_input(i)); |
1016 | 0 | } |
1017 | 0 | Ok(i.next_slice(range.start)) |
1018 | | } |
1019 | 0 | None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)), |
1020 | 0 | None => Err(ParserError::from_input(i)), |
1021 | | } |
1022 | 0 | } |
1023 | | |
1024 | | /// Return the remaining input. |
1025 | | /// |
1026 | | /// # Effective Signature |
1027 | | /// |
1028 | | /// Assuming you are parsing a `&str` [Stream]: |
1029 | | /// ```rust |
1030 | | /// # use winnow::prelude::*;; |
1031 | | /// pub fn rest<'i>(input: &mut &'i str) -> ModalResult<&'i str> |
1032 | | /// # { |
1033 | | /// # winnow::token::rest.parse_next(input) |
1034 | | /// # } |
1035 | | /// ``` |
1036 | | /// |
1037 | | /// # Example |
1038 | | /// |
1039 | | /// ```rust |
1040 | | /// # use winnow::prelude::*; |
1041 | | /// # use winnow::error::ContextError; |
1042 | | /// use winnow::token::rest; |
1043 | | /// assert_eq!(rest::<_,ContextError>.parse_peek("abc"), Ok(("", "abc"))); |
1044 | | /// assert_eq!(rest::<_,ContextError>.parse_peek(""), Ok(("", ""))); |
1045 | | /// ``` |
1046 | | #[inline] |
1047 | 0 | pub fn rest<Input, Error>(input: &mut Input) -> Result<<Input as Stream>::Slice, Error> |
1048 | 0 | where |
1049 | 0 | Input: Stream, |
1050 | 0 | Error: ParserError<Input>, |
1051 | | { |
1052 | 0 | trace("rest", move |input: &mut Input| Ok(input.finish())).parse_next(input) |
1053 | 0 | } |
1054 | | |
1055 | | /// Return the length of the remaining input. |
1056 | | /// |
1057 | | /// <div class="warning"> |
1058 | | /// |
1059 | | /// Note: this does not advance the [`Stream`] |
1060 | | /// |
1061 | | /// </div> |
1062 | | /// |
1063 | | /// # Effective Signature |
1064 | | /// |
1065 | | /// Assuming you are parsing a `&str` [Stream]: |
1066 | | /// ```rust |
1067 | | /// # use winnow::prelude::*;; |
1068 | | /// pub fn rest_len(input: &mut &str) -> ModalResult<usize> |
1069 | | /// # { |
1070 | | /// # winnow::token::rest_len.parse_next(input) |
1071 | | /// # } |
1072 | | /// ``` |
1073 | | /// |
1074 | | /// # Example |
1075 | | /// |
1076 | | /// ```rust |
1077 | | /// # use winnow::prelude::*; |
1078 | | /// # use winnow::error::ContextError; |
1079 | | /// use winnow::token::rest_len; |
1080 | | /// assert_eq!(rest_len::<_,ContextError>.parse_peek("abc"), Ok(("abc", 3))); |
1081 | | /// assert_eq!(rest_len::<_,ContextError>.parse_peek(""), Ok(("", 0))); |
1082 | | /// ``` |
1083 | | #[inline] |
1084 | 0 | pub fn rest_len<Input, Error>(input: &mut Input) -> Result<usize, Error> |
1085 | 0 | where |
1086 | 0 | Input: Stream, |
1087 | 0 | Error: ParserError<Input>, |
1088 | | { |
1089 | 0 | trace("rest_len", move |input: &mut Input| { |
1090 | 0 | let len = input.eof_offset(); |
1091 | 0 | Ok(len) |
1092 | 0 | }) |
1093 | 0 | .parse_next(input) |
1094 | 0 | } |