somen/parser/iterable/combinator/
reduce.rs1use 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#[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 #[inline]
23 pub fn new(inner: P, f: F) -> Self {
24 Self { inner, f }
25 }
26
27 #[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#[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 #[inline]
97 pub fn new(inner: P, f: F) -> Self {
98 Self { inner, f }
99 }
100
101 #[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}