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