somen/parser/combinator/
skip.rs

1use core::pin::Pin;
2use core::task::{Context, Poll};
3use futures_core::ready;
4
5use crate::error::{Error, PolledResult, Status};
6use crate::parser::iterable::IterableParser;
7use crate::parser::utils::{merge_errors, EitherState};
8use crate::parser::Parser;
9use crate::stream::Positioned;
10
11/// A parser for method [`skip`].
12///
13/// [`skip`]: crate::parser::ParserExt::skip
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Skip<P, Q> {
16    inner: P,
17    skipped: Q,
18}
19
20impl<P, Q> Skip<P, Q> {
21    /// Creates a new instance.
22    #[inline]
23    pub fn new(inner: P, skipped: Q) -> Self {
24        Self { inner, skipped }
25    }
26
27    /// Extracts the inner parser.
28    #[inline]
29    pub fn into_inner(self) -> (P, Q) {
30        (self.inner, self.skipped)
31    }
32}
33
34crate::parser_state! {
35    pub struct SkipState<I, P: Parser, Q: Parser> {
36        inner: EitherState<P::State, Q::State>,
37        #[opt]
38        output: P::Output,
39        error: Option<Error<I::Locator>>,
40    }
41}
42
43impl<P, Q, I> Parser<I> for Skip<P, Q>
44where
45    P: Parser<I>,
46    Q: Parser<I>,
47    I: Positioned + ?Sized,
48{
49    type Output = P::Output;
50    type State = SkipState<I, P, Q>;
51
52    fn poll_parse(
53        &mut self,
54        mut input: Pin<&mut I>,
55        cx: &mut Context<'_>,
56        state: &mut Self::State,
57    ) -> PolledResult<Self::Output, I> {
58        if let EitherState::Left(inner) = &mut state.inner {
59            match ready!(self.inner.poll_parse(input.as_mut(), cx, inner)?) {
60                Status::Success(val, err) => {
61                    state.output = Some(val);
62                    state.inner = EitherState::new_right();
63                    state.error = err;
64                }
65                failure => return Poll::Ready(Ok(failure)),
66            }
67        }
68
69        self.skipped
70            .poll_parse(input, cx, state.inner.right())
71            .map_ok(|status| match status {
72                Status::Success(_, err) => {
73                    merge_errors(&mut state.error, err);
74                    Status::Success(state.output(), state.error())
75                }
76                Status::Failure(err, false) => {
77                    merge_errors(&mut state.error, Some(err));
78                    Status::Failure(state.error().unwrap(), false)
79                }
80                Status::Failure(err, true) => Status::Failure(err, true),
81            })
82    }
83}
84
85crate::parser_state! {
86    pub struct SkipIterableState<I, P: IterableParser, Q: Parser> {
87        inner: EitherState<P::State, Q::State>,
88        error: Option<Error<I::Locator>>,
89    }
90}
91
92impl<P, Q, I> IterableParser<I> for Skip<P, Q>
93where
94    P: IterableParser<I>,
95    Q: Parser<I>,
96    I: Positioned + ?Sized,
97{
98    type Item = P::Item;
99    type State = SkipIterableState<I, P, Q>;
100
101    fn poll_parse_next(
102        &mut self,
103        mut input: Pin<&mut I>,
104        cx: &mut Context<'_>,
105        state: &mut Self::State,
106    ) -> PolledResult<Option<Self::Item>, I> {
107        if let EitherState::Left(inner) = &mut state.inner {
108            match ready!(self.inner.poll_parse_next(input.as_mut(), cx, inner))? {
109                Status::Success(None, err) => {
110                    state.inner = EitherState::new_right();
111                    state.error = err;
112                }
113                res => return Poll::Ready(Ok(res)),
114            }
115        }
116
117        self.skipped
118            .poll_parse(input, cx, state.inner.right())
119            .map_ok(|status| match status {
120                Status::Success(_, err) => {
121                    merge_errors(&mut state.error, err);
122                    Status::Success(None, state.error())
123                }
124                Status::Failure(err, false) => {
125                    merge_errors(&mut state.error, Some(err));
126                    Status::Failure(state.error().unwrap(), false)
127                }
128                Status::Failure(err, true) => Status::Failure(err, true),
129            })
130    }
131
132    #[inline]
133    fn size_hint(&self) -> (usize, Option<usize>) {
134        self.inner.size_hint()
135    }
136}