• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Module containing zero-copy parsers.
2 //!
3 //! These parsers require the [`RangeStream`][] bound instead of a plain [`Stream`][].
4 //!
5 //! [`RangeStream`]: ../../stream/trait.RangeStream.html
6 //! [`Stream`]: ../../stream/trait.Stream.html
7 
8 use crate::{
9     error::{
10         self, ParseError,
11         ParseResult::{self, *},
12         ResultExt, StreamError, Tracked,
13     },
14     lib::{convert::TryFrom, marker::PhantomData},
15     parser::ParseMode,
16 };
17 
18 #[cfg(feature = "std")]
19 use crate::lib::error::Error as StdError;
20 
21 #[cfg(not(feature = "std"))]
22 use crate::lib::fmt;
23 
24 use crate::stream::{
25     uncons_range, uncons_while, uncons_while1, wrap_stream_error, Range as StreamRange,
26     RangeStream, StreamErrorFor, StreamOnce,
27 };
28 
29 use crate::Parser;
30 
31 pub struct Range<Input>(Input::Range)
32 where
33     Input: RangeStream;
34 
35 impl<Input> Parser<Input> for Range<Input>
36 where
37     Input: RangeStream,
38     Input::Range: PartialEq + crate::stream::Range,
39 {
40     type Output = Input::Range;
41     type PartialState = ();
42 
43     #[inline]
parse_lazy( &mut self, input: &mut Input, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>44     fn parse_lazy(
45         &mut self,
46         input: &mut Input,
47     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
48         use crate::stream::Range;
49 
50         let position = input.position();
51         match input.uncons_range(self.0.len()) {
52             Ok(other) => {
53                 if other == self.0 {
54                     CommitOk(other)
55                 } else {
56                     PeekErr(Input::Error::empty(position).into())
57                 }
58             }
59             Err(err) => wrap_stream_error(input, err),
60         }
61     }
add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>)62     fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
63         // TODO Add unexpected message?
64         errors.error.add_expected(error::Range(self.0.clone()));
65     }
66 }
67 
68 parser! {
69     #[derive(Clone)]
70     pub struct Recognize;
71     type PartialState = <RecognizeWithValue<P> as Parser<Input>>::PartialState;
72     /// Zero-copy parser which returns committed input range.
73     ///
74     /// [`combinator::recognize`][] is a non-`RangeStream` alternative.
75     ///
76     /// [`combinator::recognize`]: ../../parser/combinator/fn.recognize.html
77     /// ```
78     /// # extern crate combine;
79     /// # use combine::parser::range::recognize;
80     /// # use combine::parser::char::letter;
81     /// # use combine::*;
82     /// # fn main() {
83     /// let mut parser = recognize(skip_many1(letter()));
84     /// assert_eq!(parser.parse("hello world"), Ok(("hello", " world")));
85     /// assert!(parser.parse("!").is_err());
86     /// # }
87     /// ```
88     #[inline]
89     pub fn recognize[Input, P](parser: P)(Input) -> <Input as StreamOnce>::Range
90     where [
91         P: Parser<Input>,
92         Input: RangeStream,
93         <Input as StreamOnce>::Range: crate::stream::Range,
94     ]
95     {
96         recognize_with_value(parser).map(|(range, _)| range)
97     }
98 }
99 
100 #[inline]
parse_partial_range<M, F, G, S, Input>( mode: M, input: &mut Input, distance_state: &mut usize, state: S, first: F, resume: G, ) -> ParseResult<Input::Range, Input::Error> where M: ParseMode, F: FnOnce(&mut Input, S) -> ParseResult<Input::Range, <Input as StreamOnce>::Error>, G: FnOnce(&mut Input, S) -> ParseResult<Input::Range, <Input as StreamOnce>::Error>, Input: RangeStream,101 fn parse_partial_range<M, F, G, S, Input>(
102     mode: M,
103     input: &mut Input,
104     distance_state: &mut usize,
105     state: S,
106     first: F,
107     resume: G,
108 ) -> ParseResult<Input::Range, Input::Error>
109 where
110     M: ParseMode,
111     F: FnOnce(&mut Input, S) -> ParseResult<Input::Range, <Input as StreamOnce>::Error>,
112     G: FnOnce(&mut Input, S) -> ParseResult<Input::Range, <Input as StreamOnce>::Error>,
113     Input: RangeStream,
114 {
115     let before = input.checkpoint();
116 
117     if !input.is_partial() {
118         first(input, state)
119     } else if mode.is_first() || *distance_state == 0 {
120         let result = first(input, state);
121         if let CommitErr(_) = result {
122             *distance_state = input.distance(&before);
123             ctry!(input.reset(before).committed());
124         }
125         result
126     } else {
127         if input.uncons_range(*distance_state).is_err() {
128             panic!("recognize errored when restoring the input stream to its expected state");
129         }
130 
131         match resume(input, state) {
132             CommitOk(_) | PeekOk(_) => (),
133             PeekErr(err) => return PeekErr(err),
134             CommitErr(err) => {
135                 *distance_state = input.distance(&before);
136                 ctry!(input.reset(before).committed());
137                 return CommitErr(err);
138             }
139         }
140 
141         let distance = input.distance(&before);
142         ctry!(input.reset(before).committed());
143         take(distance).parse_lazy(input).map(|range| {
144             *distance_state = 0;
145             range
146         })
147     }
148 }
149 
150 #[derive(Clone)]
151 pub struct RecognizeWithValue<P>(P);
152 
153 impl<Input, P> Parser<Input> for RecognizeWithValue<P>
154 where
155     P: Parser<Input>,
156     Input: RangeStream,
157     <Input as StreamOnce>::Range: crate::stream::Range,
158 {
159     type Output = (<Input as StreamOnce>::Range, P::Output);
160     type PartialState = (usize, P::PartialState);
161 
162     parse_mode!(Input);
163     #[inline]
parse_mode<M>( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> where M: ParseMode,164     fn parse_mode<M>(
165         &mut self,
166         mode: M,
167         input: &mut Input,
168         state: &mut Self::PartialState,
169     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
170     where
171         M: ParseMode,
172     {
173         let (ref mut distance_state, ref mut child_state) = *state;
174 
175         let before = input.checkpoint();
176         if !mode.is_first() && input.uncons_range(*distance_state).is_err() {
177             panic!("recognize errored when restoring the input stream to its expected state");
178         }
179 
180         let value = match self.0.parse_mode(mode, input, child_state) {
181             CommitOk(x) | PeekOk(x) => x,
182             PeekErr(err) => return PeekErr(err),
183             CommitErr(err) => {
184                 *distance_state = input.distance(&before);
185                 ctry!(input.reset(before).committed());
186                 return CommitErr(err);
187             }
188         };
189 
190         let distance = input.distance(&before);
191         ctry!(input.reset(before).committed());
192         take(distance).parse_lazy(input).map(|range| {
193             *distance_state = 0;
194             (range, value)
195         })
196     }
add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>)197     fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
198         self.0.add_error(errors)
199     }
200 }
201 
202 /// Zero-copy parser which returns a pair: (committed input range, parsed value).
203 ///
204 ///
205 /// [`combinator::recognize_with_value`] is a non-`RangeStream` alternative.
206 ///
207 /// [`combinator::recognize_with_value`]: recognize_with_value
208 /// ```
209 /// # extern crate combine;
210 /// # use combine::parser::range::recognize_with_value;
211 /// # use combine::parser::char::{digit, char};
212 /// # use combine::*;
213 /// # fn main() {
214 /// let mut parser = recognize_with_value((
215 ///     skip_many1(digit()),
216 ///     optional((attempt(char('.')), skip_many1(digit()))),
217 /// ).map(|(_, opt)| opt.is_some()));
218 ///
219 /// assert_eq!(parser.parse("1234!"), Ok((("1234", false), "!")));
220 /// assert_eq!(parser.parse("1234.0001!"), Ok((("1234.0001", true), "!")));
221 /// assert!(parser.parse("!").is_err());
222 /// assert!(parser.parse("1234.").is_err());
223 /// # }
224 /// ```
recognize_with_value<Input, P>(parser: P) -> RecognizeWithValue<P> where P: Parser<Input>, Input: RangeStream, <Input as StreamOnce>::Range: crate::stream::Range,225 pub fn recognize_with_value<Input, P>(parser: P) -> RecognizeWithValue<P>
226 where
227     P: Parser<Input>,
228     Input: RangeStream,
229     <Input as StreamOnce>::Range: crate::stream::Range,
230 {
231     RecognizeWithValue(parser)
232 }
233 
234 /// Zero-copy parser which reads a range of length `i.len()` and succeeds if `i` is equal to that
235 /// range.
236 ///
237 /// [`tokens`] is a non-`RangeStream` alternative.
238 ///
239 /// [`tokens`]: super::token::tokens
240 /// ```
241 /// # extern crate combine;
242 /// # use combine::parser::range::range;
243 /// # use combine::*;
244 /// # fn main() {
245 /// let mut parser = range("hello");
246 /// let result = parser.parse("hello world");
247 /// assert_eq!(result, Ok(("hello", " world")));
248 /// let result = parser.parse("hel world");
249 /// assert!(result.is_err());
250 /// # }
251 /// ```
range<Input>(i: Input::Range) -> Range<Input> where Input: RangeStream, Input::Range: PartialEq,252 pub fn range<Input>(i: Input::Range) -> Range<Input>
253 where
254     Input: RangeStream,
255     Input::Range: PartialEq,
256 {
257     Range(i)
258 }
259 
260 pub struct Take<Input>(usize, PhantomData<fn(Input)>);
261 impl<Input> Parser<Input> for Take<Input>
262 where
263     Input: RangeStream,
264 {
265     type Output = Input::Range;
266     type PartialState = ();
267 
268     #[inline]
parse_lazy( &mut self, input: &mut Input, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>269     fn parse_lazy(
270         &mut self,
271         input: &mut Input,
272     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
273         uncons_range(input, self.0)
274     }
275 }
276 
277 /// Zero-copy parser which reads a range of length `n`.
278 ///
279 /// [`count_min_max`][] is a non-`RangeStream` alternative.
280 ///
281 /// [`count_min_max`]: ../../parser/repeat/fn.count_min_max.html
282 /// ```
283 /// # extern crate combine;
284 /// # use combine::parser::range::take;
285 /// # use combine::*;
286 /// # fn main() {
287 /// let mut parser = take(1);
288 /// let result = parser.parse("1");
289 /// assert_eq!(result, Ok(("1", "")));
290 /// let mut parser = take(4);
291 /// let result = parser.parse("123abc");
292 /// assert_eq!(result, Ok(("123a", "bc")));
293 /// let result = parser.parse("abc");
294 /// assert!(result.is_err());
295 /// # }
296 /// ```
take<Input>(n: usize) -> Take<Input> where Input: RangeStream,297 pub fn take<Input>(n: usize) -> Take<Input>
298 where
299     Input: RangeStream,
300 {
301     Take(n, PhantomData)
302 }
303 
304 pub struct TakeWhile<Input, F>(F, PhantomData<fn(Input) -> Input>);
305 impl<Input, F> Parser<Input> for TakeWhile<Input, F>
306 where
307     Input: RangeStream,
308     Input::Range: crate::stream::Range,
309     F: FnMut(Input::Token) -> bool,
310 {
311     type Output = Input::Range;
312     type PartialState = usize;
313 
314     parse_mode!(Input);
315     #[inline]
parse_mode_impl<M>( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> where M: ParseMode,316     fn parse_mode_impl<M>(
317         &mut self,
318         mode: M,
319         input: &mut Input,
320         state: &mut Self::PartialState,
321     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
322     where
323         M: ParseMode,
324     {
325         parse_partial_range(
326             mode,
327             input,
328             state,
329             &mut self.0,
330             |input, predicate| uncons_while(input, predicate),
331             |input, predicate| uncons_while(input, predicate),
332         )
333     }
334 }
335 
336 /// Zero-copy parser which reads a range of 0 or more tokens which satisfy `f`.
337 ///
338 /// [`many`][] is a non-`RangeStream` alternative.
339 ///
340 /// [`many`]: ../../parser/repeat/fn.many.html
341 /// ```
342 /// # extern crate combine;
343 /// # use combine::parser::range::take_while;
344 /// # use combine::*;
345 /// # fn main() {
346 /// let mut parser = take_while(|c: char| c.is_digit(10));
347 /// let result = parser.parse("123abc");
348 /// assert_eq!(result, Ok(("123", "abc")));
349 /// let result = parser.parse("abc");
350 /// assert_eq!(result, Ok(("", "abc")));
351 /// # }
352 /// ```
take_while<Input, F>(f: F) -> TakeWhile<Input, F> where Input: RangeStream, Input::Range: crate::stream::Range, F: FnMut(Input::Token) -> bool,353 pub fn take_while<Input, F>(f: F) -> TakeWhile<Input, F>
354 where
355     Input: RangeStream,
356     Input::Range: crate::stream::Range,
357     F: FnMut(Input::Token) -> bool,
358 {
359     TakeWhile(f, PhantomData)
360 }
361 
362 pub struct TakeWhile1<Input, F>(F, PhantomData<fn(Input) -> Input>);
363 impl<Input, F> Parser<Input> for TakeWhile1<Input, F>
364 where
365     Input: RangeStream,
366     Input::Range: crate::stream::Range,
367     F: FnMut(Input::Token) -> bool,
368 {
369     type Output = Input::Range;
370     type PartialState = usize;
371 
372     parse_mode!(Input);
373     #[inline]
parse_mode_impl<M>( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> where M: ParseMode,374     fn parse_mode_impl<M>(
375         &mut self,
376         mode: M,
377         input: &mut Input,
378         state: &mut Self::PartialState,
379     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
380     where
381         M: ParseMode,
382     {
383         parse_partial_range(
384             mode,
385             input,
386             state,
387             &mut self.0,
388             |input, predicate| uncons_while1(input, predicate),
389             |input, predicate| uncons_while(input, predicate),
390         )
391     }
392 }
393 
394 /// Zero-copy parser which reads a range of 1 or more tokens which satisfy `f`.
395 ///
396 /// [`many1`][] is a non-`RangeStream` alternative.
397 ///
398 /// [`many1`]: ../../parser/repeat/fn.many1.html
399 /// ```
400 /// # extern crate combine;
401 /// # use combine::parser::range::take_while1;
402 /// # use combine::*;
403 /// # fn main() {
404 /// let mut parser = take_while1(|c: char| c.is_digit(10));
405 /// let result = parser.parse("123abc");
406 /// assert_eq!(result, Ok(("123", "abc")));
407 /// let result = parser.parse("abc");
408 /// assert!(result.is_err());
409 /// # }
410 /// ```
take_while1<Input, F>(f: F) -> TakeWhile1<Input, F> where Input: RangeStream, Input::Range: crate::stream::Range, F: FnMut(Input::Token) -> bool,411 pub fn take_while1<Input, F>(f: F) -> TakeWhile1<Input, F>
412 where
413     Input: RangeStream,
414     Input::Range: crate::stream::Range,
415     F: FnMut(Input::Token) -> bool,
416 {
417     TakeWhile1(f, PhantomData)
418 }
419 
420 pub struct TakeUntilRange<Input>(Input::Range)
421 where
422     Input: RangeStream;
423 impl<Input> Parser<Input> for TakeUntilRange<Input>
424 where
425     Input: RangeStream,
426     Input::Range: PartialEq + crate::stream::Range,
427 {
428     type Output = Input::Range;
429     type PartialState = usize;
430 
431     #[inline]
parse_partial( &mut self, input: &mut Input, to_consume: &mut Self::PartialState, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>432     fn parse_partial(
433         &mut self,
434         input: &mut Input,
435         to_consume: &mut Self::PartialState,
436     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
437         use crate::stream::Range;
438 
439         let len = self.0.len();
440         let before = input.checkpoint();
441         let mut first_stream_error = None;
442 
443         // Skip until the end of the last parse attempt
444         ctry!(uncons_range(input, *to_consume));
445 
446         loop {
447             let look_ahead_input = input.checkpoint();
448 
449             match input.uncons_range(len) {
450                 Ok(xs) => {
451                     if xs == self.0 {
452                         let distance = input.distance(&before) - len;
453                         ctry!(input.reset(before).committed());
454 
455                         if let Ok(committed) = input.uncons_range(distance) {
456                             if distance == 0 {
457                                 return PeekOk(committed);
458                             } else {
459                                 *to_consume = 0;
460                                 return CommitOk(committed);
461                             }
462                         }
463 
464                         // We are guaranteed able to uncons to_consume characters here
465                         // because we've already done it on look_ahead_input.
466                         unreachable!();
467                     } else {
468                         // Reset the stream back to where it was when we entered the top of the loop
469                         ctry!(input.reset(look_ahead_input).committed());
470 
471                         // Advance the stream by one token
472                         if input.uncons().is_err() {
473                             unreachable!();
474                         }
475                     }
476                 }
477                 Err(first_error) => {
478                     // If we are unable to find a successful parse even after advancing with `uncons`
479                     // below we must reset the stream to its state before the first error.
480                     // If we don't we may try and match the range `::` against `:<EOF>` which would
481                     // fail as only one `:` is present at this parse attempt. But when we later resume
482                     // with more input we must start parsing again at the first time we errored so we
483                     // can see the entire `::`
484                     if first_stream_error.is_none() {
485                         first_stream_error = Some((first_error, input.distance(&before)));
486                     }
487 
488                     // Reset the stream back to where it was when we entered the top of the loop
489                     ctry!(input.reset(look_ahead_input).committed());
490 
491                     // See if we can advance anyway
492                     if input.uncons().is_err() {
493                         let (first_error, first_error_distance) = first_stream_error.unwrap();
494 
495                         // Reset the stream
496                         ctry!(input.reset(before).committed());
497                         *to_consume = first_error_distance;
498 
499                         // Return the original error if uncons failed
500                         return wrap_stream_error(input, first_error);
501                     }
502                 }
503             };
504         }
505     }
506 }
507 
508 /// Zero-copy parser which reads a range of 0 or more tokens until `r` is found.
509 ///
510 /// The range `r` will not be committed. If `r` is not found, the parser will
511 /// return an error.
512 ///
513 /// [`repeat::take_until`][] is a non-`RangeStream` alternative.
514 ///
515 /// [`repeat::take_until`]: ../../parser/repeat/fn.take_until.html
516 /// ```
517 /// # extern crate combine;
518 /// # use combine::parser::range::{range, take_until_range};
519 /// # use combine::*;
520 /// # fn main() {
521 /// let mut parser = take_until_range("\r\n");
522 /// let result = parser.parse("To: user@example.com\r\n");
523 /// assert_eq!(result, Ok(("To: user@example.com", "\r\n")));
524 /// let result = parser.parse("Hello, world\n");
525 /// assert!(result.is_err());
526 /// # }
527 /// ```
take_until_range<Input>(r: Input::Range) -> TakeUntilRange<Input> where Input: RangeStream,528 pub fn take_until_range<Input>(r: Input::Range) -> TakeUntilRange<Input>
529 where
530     Input: RangeStream,
531 {
532     TakeUntilRange(r)
533 }
534 
535 #[derive(Debug, PartialEq)]
536 pub enum TakeRange {
537     /// Found the pattern at this offset
538     Found(usize),
539     /// Did not find the pattern but the parser can skip ahead to this offset.
540     NotFound(usize),
541 }
542 
543 impl From<Option<usize>> for TakeRange {
from(opt: Option<usize>) -> TakeRange544     fn from(opt: Option<usize>) -> TakeRange {
545         match opt {
546             Some(i) => TakeRange::Found(i),
547             None => TakeRange::NotFound(0),
548         }
549     }
550 }
551 
552 pub struct TakeFn<F, Input> {
553     searcher: F,
554     _marker: PhantomData<fn(Input)>,
555 }
556 
557 impl<Input, F, R> Parser<Input> for TakeFn<F, Input>
558 where
559     F: FnMut(Input::Range) -> R,
560     R: Into<TakeRange>,
561     Input: RangeStream,
562     Input::Range: crate::stream::Range,
563 {
564     type Output = Input::Range;
565     type PartialState = usize;
566 
567     parse_mode!(Input);
568     #[inline]
parse_mode<M>( &mut self, mode: M, input: &mut Input, offset: &mut Self::PartialState, ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> where M: ParseMode,569     fn parse_mode<M>(
570         &mut self,
571         mode: M,
572         input: &mut Input,
573         offset: &mut Self::PartialState,
574     ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
575     where
576         M: ParseMode,
577     {
578         let checkpoint = input.checkpoint();
579 
580         if mode.is_first() {
581             *offset = 0;
582         } else {
583             let _ = input.uncons_range(*offset);
584         }
585 
586         match (self.searcher)(input.range()).into() {
587             TakeRange::Found(i) => {
588                 ctry!(input.reset(checkpoint).committed());
589                 let result = uncons_range(input, *offset + i);
590                 if result.is_ok() {
591                     *offset = 0;
592                 }
593                 result
594             }
595             TakeRange::NotFound(next_offset) => {
596                 *offset = next_offset;
597 
598                 let range = input.range();
599                 let _ = input.uncons_range(range.len());
600                 let position = input.position();
601                 ctry!(input.reset(checkpoint).committed());
602 
603                 let err = Input::Error::from_error(position, StreamError::end_of_input());
604                 if !input.is_partial() && range.is_empty() {
605                     PeekErr(err.into())
606                 } else {
607                     CommitErr(err)
608                 }
609             }
610         }
611     }
612 }
613 
614 /// Searches the entire range using `searcher` and then consumes a range of `Some(n)`.
615 /// If `f` can not find anything in the range it must return `None/NotFound` which indicates an end of input error.
616 ///
617 /// If partial parsing is used the `TakeRange` enum can be returned instead of `Option`. By
618 /// returning `TakeRange::NotFound(n)` it indicates that the input can skip ahead until `n`
619 /// when parsing is next resumed.
620 ///
621 /// See [`take_until_bytes`](../byte/fn.take_until_bytes.html) for a usecase.
take_fn<F, R, Input>(searcher: F) -> TakeFn<F, Input> where F: FnMut(Input::Range) -> R, R: Into<TakeRange>, Input: RangeStream, Input::Range: crate::stream::Range,622 pub fn take_fn<F, R, Input>(searcher: F) -> TakeFn<F, Input>
623 where
624     F: FnMut(Input::Range) -> R,
625     R: Into<TakeRange>,
626     Input: RangeStream,
627     Input::Range: crate::stream::Range,
628 {
629     TakeFn {
630         searcher,
631         _marker: PhantomData,
632     }
633 }
634 
635 #[cfg(feature = "std")]
636 parser! {
637 /// Takes a parser which parses a `length` then extracts a range of that length and returns it.
638 /// Commonly used in binary formats
639 ///
640 /// ```
641 /// # use combine::parser::{byte::num::be_u16, range::length_prefix};
642 /// # use combine::*;
643 /// # fn main() {
644 /// let mut input = Vec::new();
645 /// input.extend_from_slice(&3u16.to_be_bytes());
646 /// input.extend_from_slice(b"1234");
647 ///
648 /// let mut parser = length_prefix(be_u16());
649 /// let result = parser.parse(&input[..]);
650 /// assert_eq!(result, Ok((&b"123"[..], &b"4"[..])));
651 /// # }
652 /// ```
653 pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
654 where [
655     Input: RangeStream,
656     P: Parser<Input>,
657     usize: TryFrom<P::Output>,
658     <usize as TryFrom<P::Output>>::Error: StdError + Send + Sync + 'static,
659 ]
660 {
661     len
662         .and_then(|u| {
663             usize::try_from(u)
664                 .map_err(StreamErrorFor::<Input>::other)
665         })
666         .then_partial(|&mut len| take(len))
667 }
668 }
669 
670 #[cfg(not(feature = "std"))]
671 parser! {
672 /// Takes a parser which parses a `length` then extracts a range of that length and returns it.
673 /// Commonly used in binary formats
674 ///
675 /// ```
676 /// # use combine::parser::{byte::num::be_u16, range::length_prefix};
677 /// # use combine::*;
678 /// # fn main() {
679 /// let mut input = Vec::new();
680 /// input.extend_from_slice(&3u16.to_be_bytes());
681 /// input.extend_from_slice(b"1234");
682 ///
683 /// let mut parser = length_prefix(be_u16());
684 /// let result = parser.parse(&input[..]);
685 /// assert_eq!(result, Ok((&b"123"[..], &b"4"[..])));
686 /// # }
687 /// ```
688 pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
689 where [
690     Input: RangeStream,
691     P: Parser<Input>,
692     usize: TryFrom<P::Output>,
693     <usize as TryFrom<P::Output>>::Error: fmt::Display + Send + Sync + 'static,
694 ]
695 {
696     len
697         .and_then(|u| {
698             usize::try_from(u)
699                 .map_err(StreamErrorFor::<Input>::message_format)
700         })
701         .then_partial(|&mut len| take(len))
702 }
703 }
704 
705 #[cfg(test)]
706 mod tests {
707 
708     use crate::Parser;
709 
710     use super::*;
711 
712     #[test]
take_while_test()713     fn take_while_test() {
714         let result = take_while(|c: char| c.is_digit(10)).parse("123abc");
715         assert_eq!(result, Ok(("123", "abc")));
716         let result = take_while(|c: char| c.is_digit(10)).parse("abc");
717         assert_eq!(result, Ok(("", "abc")));
718     }
719 
720     #[test]
take_while1_test()721     fn take_while1_test() {
722         let result = take_while1(|c: char| c.is_digit(10)).parse("123abc");
723         assert_eq!(result, Ok(("123", "abc")));
724         let result = take_while1(|c: char| c.is_digit(10)).parse("abc");
725         assert!(result.is_err());
726     }
727 
728     #[test]
range_string_no_char_boundary_error()729     fn range_string_no_char_boundary_error() {
730         let mut parser = range("hello");
731         let result = parser.parse("hell\u{00EE} world");
732         assert!(result.is_err());
733     }
734 
735     #[test]
take_until_range_1()736     fn take_until_range_1() {
737         let result = take_until_range("\"").parse("Foo baz bar quux\"");
738         assert_eq!(result, Ok(("Foo baz bar quux", "\"")));
739     }
740 
741     #[test]
take_until_range_2()742     fn take_until_range_2() {
743         let result = take_until_range("===").parse("if ((pointless_comparison == 3) === true) {");
744         assert_eq!(
745             result,
746             Ok(("if ((pointless_comparison == 3) ", "=== true) {"))
747         );
748     }
749 
750     #[test]
take_until_range_unicode_1()751     fn take_until_range_unicode_1() {
752         let result = take_until_range("��")
753             .parse("�� Ferris the friendly rustacean �� and his snake friend ��");
754         assert_eq!(
755             result,
756             Ok((
757                 "�� Ferris the friendly rustacean ",
758                 "�� and his snake friend ��"
759             ))
760         );
761     }
762 
763     #[test]
take_until_range_unicode_2()764     fn take_until_range_unicode_2() {
765         let result = take_until_range("⁘⁙/⁘").parse("⚙️��️��=��️⁘⁙⁘⁘⁙/⁘⁘⁙/⁘");
766         assert_eq!(result, Ok(("⚙️��️��=��️⁘⁙⁘", "⁘⁙/⁘⁘⁙/⁘")));
767     }
768 }
769