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