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