1use 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")]
19use crate::lib::error::Error as StdError;
20
21#[cfg(not(feature = "std"))]
22use crate::lib::fmt;
23
24use crate::stream::{
25    uncons_range, uncons_while, uncons_while1, wrap_stream_error, Range as StreamRange,
26    RangeStream, StreamErrorFor, StreamOnce,
27};
28
29use crate::Parser;
30
31pub struct Range<Input>(Input::Range)
32where
33    Input: RangeStream;
34
35impl<Input> Parser<Input> for Range<Input>
36where
37    Input: RangeStream,
38    Input::Range: PartialEq + crate::stream::Range,
39{
40    type Output = Input::Range;
41    type PartialState = ();
42
43    #[inline]
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    }
62    fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
63        errors.error.add_expected(error::Range(self.0.clone()));
65    }
66}
67
68parser! {
69    #[derive(Clone)]
70    pub struct Recognize;
71    type PartialState = <RecognizeWithValue<P> as Parser<Input>>::PartialState;
72    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]
100fn 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>
108where
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)]
150pub struct RecognizeWithValue<P>(P);
151
152impl<Input, P> Parser<Input> for RecognizeWithValue<P>
153where
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]
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    }
196    fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
197        self.0.add_error(errors)
198    }
199}
200
201pub fn recognize_with_value<Input, P>(parser: P) -> RecognizeWithValue<P>
225where
226    P: Parser<Input>,
227    Input: RangeStream,
228    <Input as StreamOnce>::Range: crate::stream::Range,
229{
230    RecognizeWithValue(parser)
231}
232
233pub fn range<Input>(i: Input::Range) -> Range<Input>
252where
253    Input: RangeStream,
254    Input::Range: PartialEq,
255{
256    Range(i)
257}
258
259pub struct Take<Input>(usize, PhantomData<fn(Input)>);
260impl<Input> Parser<Input> for Take<Input>
261where
262    Input: RangeStream,
263{
264    type Output = Input::Range;
265    type PartialState = ();
266
267    #[inline]
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
276pub fn take<Input>(n: usize) -> Take<Input>
297where
298    Input: RangeStream,
299{
300    Take(n, PhantomData)
301}
302
303pub struct TakeWhile<Input, F>(F, PhantomData<fn(Input) -> Input>);
304impl<Input, F> Parser<Input> for TakeWhile<Input, F>
305where
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]
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
335pub fn take_while<Input, F>(f: F) -> TakeWhile<Input, F>
353where
354    Input: RangeStream,
355    Input::Range: crate::stream::Range,
356    F: FnMut(Input::Token) -> bool,
357{
358    TakeWhile(f, PhantomData)
359}
360
361pub struct TakeWhile1<Input, F>(F, PhantomData<fn(Input) -> Input>);
362impl<Input, F> Parser<Input> for TakeWhile1<Input, F>
363where
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]
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
393pub fn take_while1<Input, F>(f: F) -> TakeWhile1<Input, F>
411where
412    Input: RangeStream,
413    Input::Range: crate::stream::Range,
414    F: FnMut(Input::Token) -> bool,
415{
416    TakeWhile1(f, PhantomData)
417}
418
419pub struct TakeUntilRange<Input>(Input::Range)
420where
421    Input: RangeStream;
422impl<Input> Parser<Input> for TakeUntilRange<Input>
423where
424    Input: RangeStream,
425    Input::Range: PartialEq + crate::stream::Range,
426{
427    type Output = Input::Range;
428    type PartialState = usize;
429
430    #[inline]
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        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                        unreachable!();
466                    } else {
467                        ctry!(input.reset(look_ahead_input).committed());
469
470                        if input.uncons().is_err() {
472                            unreachable!();
473                        }
474                    }
475                }
476                Err(first_error) => {
477                    if first_stream_error.is_none() {
484                        first_stream_error = Some((first_error, input.distance(&before)));
485                    }
486
487                    ctry!(input.reset(look_ahead_input).committed());
489
490                    if input.uncons().is_err() {
492                        let (first_error, first_error_distance) = first_stream_error.unwrap();
493
494                        ctry!(input.reset(before).committed());
496                        *to_consume = first_error_distance;
497
498                        return wrap_stream_error(input, first_error);
500                    }
501                }
502            };
503        }
504    }
505}
506
507pub fn take_until_range<Input>(r: Input::Range) -> TakeUntilRange<Input>
528where
529    Input: RangeStream,
530{
531    TakeUntilRange(r)
532}
533
534#[derive(Debug, PartialEq)]
535pub enum TakeRange {
536    Found(usize),
538    NotFound(usize),
540}
541
542impl From<Option<usize>> for TakeRange {
543    fn from(opt: Option<usize>) -> TakeRange {
544        match opt {
545            Some(i) => TakeRange::Found(i),
546            None => TakeRange::NotFound(0),
547        }
548    }
549}
550
551pub struct TakeFn<F, Input> {
552    searcher: F,
553    _marker: PhantomData<fn(Input)>,
554}
555
556impl<Input, F, R> Parser<Input> for TakeFn<F, Input>
557where
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]
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
613pub fn take_fn<F, R, Input>(searcher: F) -> TakeFn<F, Input>
622where
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")]
635parser! {
636pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
653where [
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"))]
670parser! {
671pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
688where [
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)]
705mod tests {
706
707    use crate::Parser;
708
709    use super::*;
710
711    #[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]
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]
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]
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]
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]
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]
763    fn take_until_range_unicode_2() {
764        let result = take_until_range("⁘⁙/⁘").parse("⚙️🛠️🦀=🏎️⁘⁙⁘⁘⁙/⁘⁘⁙/⁘");
765        assert_eq!(result, Ok(("⚙️🛠️🦀=🏎️⁘⁙⁘", "⁘⁙/⁘⁘⁙/⁘")));
766    }
767}