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