somen/parser/iterable/combinator/
reduce.rs

1use core::pin::Pin;
2use core::task::{Context, Poll};
3use futures_core::ready;
4
5use crate::error::{Error, Expects, PolledResult, Status};
6use crate::parser::iterable::IterableParser;
7use crate::parser::utils::merge_errors;
8use crate::parser::Parser;
9use crate::stream::Positioned;
10
11/// A parser for method [`reduce`].
12///
13/// [`reduce`]: crate::parser::iterable::IterableParserExt::reduce
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Reduce<P, F> {
16    inner: P,
17    f: F,
18}
19
20impl<P, F> Reduce<P, F> {
21    /// Creates a new instance.
22    #[inline]
23    pub fn new(inner: P, f: F) -> Self {
24        Self { inner, f }
25    }
26
27    /// Extracts the inner parser.
28    #[inline]
29    pub fn into_inner(self) -> P {
30        self.inner
31    }
32}
33
34crate::parser_state! {
35    pub struct ReduceState<I, P: IterableParser> {
36        inner: P::State,
37        acc: Option<P::Item>,
38        error: Option<Error<I::Locator>>,
39    }
40}
41
42impl<P, F, I> Parser<I> for Reduce<P, F>
43where
44    P: IterableParser<I>,
45    F: FnMut(P::Item, P::Item) -> P::Item,
46    I: Positioned + ?Sized,
47{
48    type Output = Option<P::Item>;
49    type State = ReduceState<I, P>;
50
51    fn poll_parse(
52        &mut self,
53        mut input: Pin<&mut I>,
54        cx: &mut Context<'_>,
55        state: &mut Self::State,
56    ) -> PolledResult<Self::Output, I> {
57        Poll::Ready(Ok(loop {
58            match ready!(self
59                .inner
60                .poll_parse_next(input.as_mut(), cx, &mut state.inner)?)
61            {
62                Status::Success(Some(val), err) => {
63                    merge_errors(&mut state.error, err);
64                    state.acc = Some(match state.acc() {
65                        Some(acc) => (self.f)(acc, val),
66                        None => val,
67                    });
68                }
69                Status::Success(None, err) => {
70                    merge_errors(&mut state.error, err);
71                    break Status::Success(state.acc(), state.error());
72                }
73                Status::Failure(err, false) => {
74                    merge_errors(&mut state.error, Some(err));
75                    break Status::Failure(state.error().unwrap(), false);
76                }
77                Status::Failure(err, true) => {
78                    break Status::Failure(err, true);
79                }
80            }
81        }))
82    }
83}
84
85/// A parser for method [`try_reduce`].
86///
87/// [`try_reduce`]: crate::parser::iterable::IterableParserExt::try_reduce
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct TryReduce<P, F> {
90    inner: P,
91    f: F,
92}
93
94impl<P, F> TryReduce<P, F> {
95    /// Creates a new instance.
96    #[inline]
97    pub fn new(inner: P, f: F) -> Self {
98        Self { inner, f }
99    }
100
101    /// Extracts the inner parser.
102    #[inline]
103    pub fn into_inner(self) -> P {
104        self.inner
105    }
106}
107
108crate::parser_state! {
109    pub struct TryReduceState<I, P: IterableParser> {
110        inner: P::State,
111        acc: Option<P::Item>,
112        #[opt(set = set_start)]
113        start: I::Locator,
114        error: Option<Error<I::Locator>>,
115    }
116}
117
118impl<P, F, E, I> Parser<I> for TryReduce<P, F>
119where
120    P: IterableParser<I>,
121    F: FnMut(P::Item, P::Item) -> Result<P::Item, E>,
122    E: Into<Expects>,
123    I: Positioned + ?Sized,
124{
125    type Output = Option<P::Item>;
126    type State = TryReduceState<I, P>;
127
128    fn poll_parse(
129        &mut self,
130        mut input: Pin<&mut I>,
131        cx: &mut Context<'_>,
132        state: &mut Self::State,
133    ) -> PolledResult<Self::Output, I> {
134        Poll::Ready(Ok(loop {
135            state.set_start(|| input.position());
136            match ready!(self
137                .inner
138                .poll_parse_next(input.as_mut(), cx, &mut state.inner)?)
139            {
140                Status::Success(Some(val), err) => {
141                    merge_errors(&mut state.error, err);
142                    state.acc = Some(match state.acc() {
143                        Some(acc) => match (self.f)(acc, val) {
144                            Ok(res) => {
145                                state.start = None;
146                                res
147                            }
148                            Err(exp) => {
149                                break Status::Failure(
150                                    Error {
151                                        expects: exp.into(),
152                                        position: state.start()..input.position(),
153                                    },
154                                    true,
155                                )
156                            }
157                        },
158                        None => {
159                            state.start = None;
160                            val
161                        }
162                    });
163                }
164                Status::Success(None, err) => {
165                    merge_errors(&mut state.error, err);
166                    state.start = None;
167                    break Status::Success(state.acc(), state.error());
168                }
169                Status::Failure(err, false) => {
170                    merge_errors(&mut state.error, Some(err));
171                    state.start = None;
172                    break Status::Failure(state.error().unwrap(), false);
173                }
174                Status::Failure(err, true) => {
175                    state.start = None;
176                    break Status::Failure(err, true);
177                }
178            }
179        }))
180    }
181}