winnow/token/mod.rs
1//! Parsers extracting tokens from the stream
2
3#[cfg(test)]
4mod tests;
5
6use crate::combinator::trace;
7use crate::combinator::DisplayDebug;
8use crate::error::Needed;
9use crate::error::ParserError;
10use crate::lib::std::result::Result::Ok;
11use crate::stream::Range;
12use crate::stream::{Compare, CompareResult, ContainsToken, FindSlice, Stream};
13use crate::stream::{StreamIsPartial, ToUsize};
14use crate::Parser;
15use 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")]
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/// # 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")]
160pub fn literal<Literal, Input, Error>(
161 literal: Literal,
162) -> impl Parser<Input, <Input as Stream>::Slice, Error>
163where
164 Input: StreamIsPartial + Stream + Compare<Literal>,
165 Literal: Clone + crate::lib::std::fmt::Debug,
166 Error: ParserError<Input>,
167{
168 trace(DisplayDebug(literal.clone()), move |i: &mut Input| {
169 let t = literal.clone();
170 if <Input as StreamIsPartial>::is_partial_supported() {
171 literal_::<_, _, _, true>(i, t)
172 } else {
173 literal_::<_, _, _, false>(i, t)
174 }
175 })
176}
177
178fn literal_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
179 i: &mut I,
180 t: T,
181) -> Result<<I as Stream>::Slice, Error>
182where
183 I: StreamIsPartial,
184 I: Stream + Compare<T>,
185 T: crate::lib::std::fmt::Debug,
186{
187 match i.compare(t) {
188 CompareResult::Ok(len) => Ok(i.next_slice(len)),
189 CompareResult::Incomplete if PARTIAL && i.is_partial() => {
190 Err(ParserError::incomplete(i, Needed::Unknown))
191 }
192 CompareResult::Incomplete | CompareResult::Error => Err(ParserError::from_input(i)),
193 }
194}
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")]
262pub fn one_of<Input, Set, Error>(set: Set) -> impl Parser<Input, <Input as Stream>::Token, Error>
263where
264 Input: StreamIsPartial + Stream,
265 <Input as Stream>::Token: Clone,
266 Set: ContainsToken<<Input as Stream>::Token>,
267 Error: ParserError<Input>,
268{
269 trace(
270 "one_of",
271 any.verify(move |t: &<Input as Stream>::Token| set.contains_token(t.clone())),
272 )
273}
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)]
315pub fn none_of<Input, Set, Error>(set: Set) -> impl Parser<Input, <Input as Stream>::Token, Error>
316where
317 Input: StreamIsPartial + Stream,
318 <Input as Stream>::Token: Clone,
319 Set: ContainsToken<<Input as Stream>::Token>,
320 Error: ParserError<Input>,
321{
322 trace(
323 "none_of",
324 any.verify(move |t: &<Input as Stream>::Token| !set.contains_token(t.clone())),
325 )
326}
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")]
478pub fn take_while<Set, Input, Error>(
479 occurrences: impl Into<Range>,
480 set: Set,
481) -> impl Parser<Input, <Input as Stream>::Slice, Error>
482where
483 Input: StreamIsPartial + Stream,
484 Set: ContainsToken<<Input as Stream>::Token>,
485 Error: ParserError<Input>,
486{
487 let Range {
488 start_inclusive,
489 end_inclusive,
490 } = occurrences.into();
491 trace("take_while", move |i: &mut Input| {
492 match (start_inclusive, end_inclusive) {
493 (0, None) => {
494 if <Input as StreamIsPartial>::is_partial_supported() {
495 take_till0::<_, _, _, true>(i, |c| !set.contains_token(c))
496 } else {
497 take_till0::<_, _, _, false>(i, |c| !set.contains_token(c))
498 }
499 }
500 (1, None) => {
501 if <Input as StreamIsPartial>::is_partial_supported() {
502 take_till1::<_, _, _, true>(i, |c| !set.contains_token(c))
503 } else {
504 take_till1::<_, _, _, false>(i, |c| !set.contains_token(c))
505 }
506 }
507 (start, end) => {
508 let end = end.unwrap_or(usize::MAX);
509 if <Input as StreamIsPartial>::is_partial_supported() {
510 take_till_m_n::<_, _, _, true>(i, start, end, |c| !set.contains_token(c))
511 } else {
512 take_till_m_n::<_, _, _, false>(i, start, end, |c| !set.contains_token(c))
513 }
514 }
515 }
516 })
517}
518
519fn take_till0<P, I: StreamIsPartial + Stream, E: ParserError<I>, const PARTIAL: bool>(
520 input: &mut I,
521 predicate: P,
522) -> Result<<I as Stream>::Slice, E>
523where
524 P: Fn(I::Token) -> bool,
525{
526 let offset = match input.offset_for(predicate) {
527 Some(offset) => offset,
528 None if PARTIAL && input.is_partial() => {
529 return Err(ParserError::incomplete(input, Needed::new(1)));
530 }
531 None => input.eof_offset(),
532 };
533 Ok(input.next_slice(offset))
534}
535
536fn take_till1<P, I: StreamIsPartial + Stream, E: ParserError<I>, const PARTIAL: bool>(
537 input: &mut I,
538 predicate: P,
539) -> Result<<I as Stream>::Slice, E>
540where
541 P: Fn(I::Token) -> bool,
542{
543 let offset = match input.offset_for(predicate) {
544 Some(offset) => offset,
545 None if PARTIAL && input.is_partial() => {
546 return Err(ParserError::incomplete(input, Needed::new(1)));
547 }
548 None => input.eof_offset(),
549 };
550 if offset == 0 {
551 Err(ParserError::from_input(input))
552 } else {
553 Ok(input.next_slice(offset))
554 }
555}
556
557fn take_till_m_n<P, I, Error: ParserError<I>, const PARTIAL: bool>(
558 input: &mut I,
559 m: usize,
560 n: usize,
561 predicate: P,
562) -> Result<<I as Stream>::Slice, Error>
563where
564 I: StreamIsPartial,
565 I: Stream,
566 P: Fn(I::Token) -> bool,
567{
568 if n < m {
569 return Err(ParserError::assert(
570 input,
571 "`occurrences` should be ascending, rather than descending",
572 ));
573 }
574
575 let mut final_count = 0;
576 for (processed, (offset, token)) in input.iter_offsets().enumerate() {
577 if predicate(token) {
578 if processed < m {
579 return Err(ParserError::from_input(input));
580 } else {
581 return Ok(input.next_slice(offset));
582 }
583 } else {
584 if processed == n {
585 return Ok(input.next_slice(offset));
586 }
587 final_count = processed + 1;
588 }
589 }
590 if PARTIAL && input.is_partial() {
591 if final_count == n {
592 Ok(input.finish())
593 } else {
594 let needed = if m > input.eof_offset() {
595 m - input.eof_offset()
596 } else {
597 1
598 };
599 Err(ParserError::incomplete(input, Needed::new(needed)))
600 }
601 } else {
602 if m <= final_count {
603 Ok(input.finish())
604 } else {
605 Err(ParserError::from_input(input))
606 }
607 }
608}
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")]
669pub fn take_till<Set, Input, Error>(
670 occurrences: impl Into<Range>,
671 set: Set,
672) -> impl Parser<Input, <Input as Stream>::Slice, Error>
673where
674 Input: StreamIsPartial + Stream,
675 Set: ContainsToken<<Input as Stream>::Token>,
676 Error: ParserError<Input>,
677{
678 let Range {
679 start_inclusive,
680 end_inclusive,
681 } = occurrences.into();
682 trace("take_till", move |i: &mut Input| {
683 match (start_inclusive, end_inclusive) {
684 (0, None) => {
685 if <Input as StreamIsPartial>::is_partial_supported() {
686 take_till0::<_, _, _, true>(i, |c| set.contains_token(c))
687 } else {
688 take_till0::<_, _, _, false>(i, |c| set.contains_token(c))
689 }
690 }
691 (1, None) => {
692 if <Input as StreamIsPartial>::is_partial_supported() {
693 take_till1::<_, _, _, true>(i, |c| set.contains_token(c))
694 } else {
695 take_till1::<_, _, _, false>(i, |c| set.contains_token(c))
696 }
697 }
698 (start, end) => {
699 let end = end.unwrap_or(usize::MAX);
700 if <Input as StreamIsPartial>::is_partial_supported() {
701 take_till_m_n::<_, _, _, true>(i, start, end, |c| set.contains_token(c))
702 } else {
703 take_till_m_n::<_, _, _, false>(i, start, end, |c| set.contains_token(c))
704 }
705 }
706 }
707 })
708}
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)]
781pub fn take<UsizeLike, Input, Error>(
782 token_count: UsizeLike,
783) -> impl Parser<Input, <Input as Stream>::Slice, Error>
784where
785 Input: StreamIsPartial + Stream,
786 UsizeLike: ToUsize,
787 Error: ParserError<Input>,
788{
789 let c = token_count.to_usize();
790 trace("take", move |i: &mut Input| {
791 if <Input as StreamIsPartial>::is_partial_supported() {
792 take_::<_, _, true>(i, c)
793 } else {
794 take_::<_, _, false>(i, c)
795 }
796 })
797}
798
799fn take_<I, Error: ParserError<I>, const PARTIAL: bool>(
800 i: &mut I,
801 c: usize,
802) -> Result<<I as Stream>::Slice, Error>
803where
804 I: StreamIsPartial,
805 I: Stream,
806{
807 match i.offset_at(c) {
808 Ok(offset) => Ok(i.next_slice(offset)),
809 Err(e) if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, e)),
810 Err(_needed) => Err(ParserError::from_input(i)),
811 }
812}
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)]
909pub fn take_until<Literal, Input, Error>(
910 occurrences: impl Into<Range>,
911 literal: Literal,
912) -> impl Parser<Input, <Input as Stream>::Slice, Error>
913where
914 Input: StreamIsPartial + Stream + FindSlice<Literal>,
915 Literal: Clone,
916 Error: ParserError<Input>,
917{
918 let Range {
919 start_inclusive,
920 end_inclusive,
921 } = occurrences.into();
922 trace("take_until", move |i: &mut Input| {
923 match (start_inclusive, end_inclusive) {
924 (0, None) => {
925 if <Input as StreamIsPartial>::is_partial_supported() {
926 take_until0_::<_, _, _, true>(i, literal.clone())
927 } else {
928 take_until0_::<_, _, _, false>(i, literal.clone())
929 }
930 }
931 (1, None) => {
932 if <Input as StreamIsPartial>::is_partial_supported() {
933 take_until1_::<_, _, _, true>(i, literal.clone())
934 } else {
935 take_until1_::<_, _, _, false>(i, literal.clone())
936 }
937 }
938 (start, end) => {
939 let end = end.unwrap_or(usize::MAX);
940 if <Input as StreamIsPartial>::is_partial_supported() {
941 take_until_m_n_::<_, _, _, true>(i, start, end, literal.clone())
942 } else {
943 take_until_m_n_::<_, _, _, false>(i, start, end, literal.clone())
944 }
945 }
946 }
947 })
948}
949
950fn take_until0_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
951 i: &mut I,
952 t: T,
953) -> Result<<I as Stream>::Slice, Error>
954where
955 I: StreamIsPartial,
956 I: Stream + FindSlice<T>,
957{
958 match i.find_slice(t) {
959 Some(range) => Ok(i.next_slice(range.start)),
960 None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)),
961 None => Err(ParserError::from_input(i)),
962 }
963}
964
965fn take_until1_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
966 i: &mut I,
967 t: T,
968) -> Result<<I as Stream>::Slice, Error>
969where
970 I: StreamIsPartial,
971 I: Stream + FindSlice<T>,
972{
973 match i.find_slice(t) {
974 None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)),
975 None => Err(ParserError::from_input(i)),
976 Some(range) => {
977 if range.start == 0 {
978 Err(ParserError::from_input(i))
979 } else {
980 Ok(i.next_slice(range.start))
981 }
982 }
983 }
984}
985
986fn take_until_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
987 i: &mut I,
988 start: usize,
989 end: usize,
990 t: T,
991) -> Result<<I as Stream>::Slice, Error>
992where
993 I: StreamIsPartial,
994 I: Stream + FindSlice<T>,
995{
996 if end < start {
997 return Err(ParserError::assert(
998 i,
999 "`occurrences` should be ascending, rather than descending",
1000 ));
1001 }
1002
1003 match i.find_slice(t) {
1004 Some(range) => {
1005 let start_offset = i.offset_at(start);
1006 let end_offset = i.offset_at(end).unwrap_or_else(|_err| i.eof_offset());
1007 if start_offset.map(|s| range.start < s).unwrap_or(true) {
1008 if PARTIAL && i.is_partial() {
1009 return Err(ParserError::incomplete(i, Needed::Unknown));
1010 } else {
1011 return Err(ParserError::from_input(i));
1012 }
1013 }
1014 if end_offset < range.start {
1015 return Err(ParserError::from_input(i));
1016 }
1017 Ok(i.next_slice(range.start))
1018 }
1019 None if PARTIAL && i.is_partial() => Err(ParserError::incomplete(i, Needed::Unknown)),
1020 None => Err(ParserError::from_input(i)),
1021 }
1022}
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]
1047pub fn rest<Input, Error>(input: &mut Input) -> Result<<Input as Stream>::Slice, Error>
1048where
1049 Input: Stream,
1050 Error: ParserError<Input>,
1051{
1052 trace("rest", move |input: &mut Input| Ok(input.finish())).parse_next(input)
1053}
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]
1084pub fn rest_len<Input, Error>(input: &mut Input) -> Result<usize, Error>
1085where
1086 Input: Stream,
1087 Error: ParserError<Input>,
1088{
1089 trace("rest_len", move |input: &mut Input| {
1090 let len = input.eof_offset();
1091 Ok(len)
1092 })
1093 .parse_next(input)
1094}