Coverage Report

Created: 2026-02-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}