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