Thanks to visit codestin.com
Credit goes to docs.rs

fabparse/
repeat.rs

1use std::{
2    convert::Infallible,
3    error::Error,
4    fmt::Display,
5    marker::PhantomData,
6    ops::{Range, RangeBounds},
7};
8
9use crate::{sequence::Sequence, Parser, ParserError, ParserType};
10/**
11 * Repeat parsers can be customized with a custom try reduce function, see the TryReducer trait.
12 * This error will be used for reducers that return Option<()> or
13 * bool.
14 *
15 * Reducers that return Result<(),E> will use the E from the result,
16 * and reducers that return () will never fail.
17 */
18#[derive(Clone, Debug, Copy)]
19pub struct TryReducerError;
20impl Display for TryReducerError {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.write_str("TryReducerFailed")
23    }
24}
25
26impl Error for TryReducerError {}
27
28/**
29 * Repeat parsers by default return a Vec. This behavior can be replaced with
30 * with the method `parser.reduce(acc, fn)`, where accumulator implements
31 * TryReducer. This trait is already implemented for all of `[fn(&mut acc)->(),
32 * fn(&mut acc)->Option<()>, fn(&mut acc)->bool, fn(&mut acc)->Result<(),E> ]`
33 *
34 * `Acc`: The type of the accumulator
35 *
36 * `T`: The type of the values that will be accumulated
37 *
38 * `FType`: A dummy parameter used for disambiguating trait implementations.
39 * You can use any struct defined with your crate.
40 *
41 * `FErr`: The error type of the accumutation function.
42 */
43pub trait TryReducer<'a, Acc, T, FType, FErr, Out, I: ?Sized> {
44    fn try_reduce(&self, acc: &mut Acc, val: T) -> Result<(), FErr>;
45    fn finalize(&self, acc: Acc, orig_input: &'a I, new_input: &'a I) -> Out;
46}
47
48pub struct ResultReducer;
49impl<'a, Acc, T, F, FErr, I: ?Sized> TryReducer<'a, Acc, T, ResultReducer, FErr, Acc, I> for F
50where
51    F: Fn(&mut Acc, T) -> Result<(), FErr>,
52{
53    fn try_reduce(&self, acc: &mut Acc, val: T) -> Result<(), FErr> {
54        self(acc, val)
55    }
56    fn finalize(&self, acc: Acc, _orig_input: &'a I, _new_input: &'a I) -> Acc {
57        acc
58    }
59}
60pub struct OptionReducer();
61impl<'a, Acc, T, F, I: ?Sized> TryReducer<'a, Acc, T, OptionReducer, TryReducerError, Acc, I> for F
62where
63    F: Fn(&mut Acc, T) -> Option<()>,
64{
65    fn try_reduce(&self, acc: &mut Acc, val: T) -> Result<(), TryReducerError> {
66        self(acc, val).ok_or(TryReducerError).map(|_| ())
67    }
68    fn finalize(&self, acc: Acc, _orig_input: &'a I, _new_input: &'a I) -> Acc {
69        acc
70    }
71}
72pub struct BoolReducer;
73impl<'a, Acc, T, F, I: ?Sized> TryReducer<'a, Acc, T, BoolReducer, TryReducerError, Acc, I> for F
74where
75    F: Fn(&mut Acc, T) -> bool,
76{
77    fn try_reduce(&self, acc: &mut Acc, val: T) -> Result<(), TryReducerError> {
78        if self(acc, val) {
79            Ok(())
80        } else {
81            Err(TryReducerError)
82        }
83    }
84    fn finalize(&self, acc: Acc, _orig_input: &'a I, _new_input: &'a I) -> Acc {
85        acc
86    }
87}
88
89pub struct InfallibleReducer;
90impl<'a, Acc, T, F, I: ?Sized> TryReducer<'a, Acc, T, InfallibleReducer, Infallible, Acc, I> for F
91where
92    F: Fn(&mut Acc, T) -> (),
93{
94    fn try_reduce(&self, acc: &mut Acc, val: T) -> Result<(), Infallible> {
95        Ok(self(acc, val)).map(|_| ())
96    }
97    fn finalize(&self, acc: Acc, _orig_input: &'a I, _new_input: &'a I) -> Acc {
98        acc
99    }
100}
101
102pub struct InputSliceReducer;
103impl<'a, T, I: ?Sized> TryReducer<'a, (), T, InputSliceReducer, Infallible, &'a I, I>
104    for InputSliceReducer
105where
106    I: Sequence,
107{
108    fn try_reduce(&self, _acc: &mut (), _val: T) -> Result<(), Infallible> {
109        Ok(())
110    }
111    fn finalize(&self, _acc: (), orig_input: &'a I, new_input: &'a I) -> &'a I {
112        orig_input.subtract(new_input)
113    }
114}
115
116pub struct Reducer<Reduce, Acc: Clone> {
117    pub acc: Acc,
118    pub reduce_operator: Reduce,
119}
120/**
121 * This struct can be constructed through the method `fab_repeat` on any parser.
122 * It can be customized with a min/max number of repititions, or a custom
123 * try reduce.
124 */
125pub struct Repeat<P, ParI: ?Sized, ParO, ParE, F, Acc: Clone> {
126    parser: P,
127    reducer: Reducer<F, Acc>,
128    bounds: Range<usize>,
129    phantom_i: PhantomData<ParI>,
130    phantom_o: PhantomData<ParO>,
131    phantom_e: PhantomData<ParE>,
132}
133
134impl<P, ParI: ?Sized, ParO, ParE, F, Acc: Clone> Repeat<P, ParI, ParO, ParE, F, Acc> {
135    /**
136     * Constructs a new repeat parser. Prefer to use the method `fab_repeat` in the parser trait.
137     */
138    pub fn new(parser: P, reducer: Reducer<F, Acc>, bounds: Range<usize>) -> Self {
139        Repeat {
140            parser,
141            reducer,
142            bounds,
143            phantom_i: PhantomData,
144            phantom_o: PhantomData,
145            phantom_e: PhantomData,
146        }
147    }
148}
149
150pub struct RepeatParser<PType, ReducerOut, FErr> {
151    ptype: PhantomData<PType>,
152    reducer_out: PhantomData<ReducerOut>,
153    ferr: PhantomData<FErr>,
154}
155
156fn loc<I: ?Sized>(seq: &I) -> usize {
157    seq as *const I as *const u8 as usize
158}
159
160/**
161 * This function is generics soup, but the goal is this:
162 * It repeats applying the parser until it fails or exceeds the maximum bound.
163 * It accumulates the output of the parser into Acc using F. If F returns an error
164 * the parser also fails with that error. In iterator language, this is a TryReduce operator.
165 */
166impl<'a, P, I, O, E, PType, F, Acc, FErr, ReducerOut, AccOut>
167    Parser<'a, I, AccOut, E, RepeatParser<PType, ReducerOut, FErr>> for Repeat<P, I, O, E, F, Acc>
168where
169    E: ParserError,
170    I: ?Sized + Sequence,
171    P: Parser<'a, I, O, E, PType>,
172    Acc: Clone,
173    FErr: 'static + Send + Sync + Error,
174    F: TryReducer<'a, Acc, O, ReducerOut, FErr, AccOut, I>,
175{
176    fn fab(&self, input: &mut &'a I) -> Result<AccOut, E> {
177        let mut res = self.reducer.acc.clone();
178        let mut repetitions: usize = 0;
179        let mut last_location = *input;
180        let orig_input = *input;
181        if self.bounds.is_empty() {
182            return Err(E::from_parser_error(*input, ParserType::Repeat));
183        }
184        loop {
185            // Break out of the loop early if we hit the repetition limit.
186            if repetitions == self.bounds.end - 1 {
187                return Ok(self
188                    .reducer
189                    .reduce_operator
190                    .finalize(res, orig_input, input));
191            }
192            //This will be used if the try reduce fails to get a
193            //correct location of where the parser started.
194            let loc_before_iteration = *input;
195            match self.parser.fab(input) {
196                //The parser succeeded, accumulate its output and continue parsing
197                Ok(val) => {
198                    //We made no progress, so return an error rather than looping indefinitely
199                    if loc(*input) == loc(last_location) {
200                        let mut err =
201                            E::from_parser_error(loc_before_iteration, ParserType::RepeatIter);
202                        *input = orig_input;
203                        err.add_context(orig_input, ParserType::Repeat);
204                        return Err(err);
205                    }
206                    last_location = *input;
207                    //The reduce operation can fail, so we need an if let for that case. It accumuates
208                    //results by mutable reference, so there is no need for anything in the Ok case.
209                    if let Err(err) = self.reducer.reduce_operator.try_reduce(&mut res, val) {
210                        let mut err = E::from_external_error(
211                            loc_before_iteration,
212                            ParserType::RepeatIter,
213                            err,
214                        );
215                        *input = orig_input;
216                        //Since the repeat error can occur anywhere in the sequence, add the
217                        //start of the repeat to the context.
218                        err.add_context(orig_input, ParserType::Repeat);
219                        return Err(err);
220                    }
221                }
222                Err(_) => {
223                    //The underlying parser failed, so return the results up to here.
224                    if self.bounds.contains(&repetitions) {
225                        return Ok(self
226                            .reducer
227                            .reduce_operator
228                            .finalize(res, orig_input, input));
229                    } else {
230                        *input = orig_input;
231                        return Err(E::from_parser_error(*input, ParserType::Repeat));
232                    }
233                }
234            }
235            repetitions += 1;
236        }
237    }
238}
239
240impl<P, ParI: ?Sized, ParO, ParE, F, Acc: Clone> Repeat<P, ParI, ParO, ParE, F, Acc> {
241    /**
242     * Sets an inclusive minimum number of repititions for this parser to succeed.
243     */
244    pub fn min(self, min: usize) -> Self {
245        Repeat::new(self.parser, self.reducer, min..self.bounds.end)
246    }
247    /**
248     * Sets as exclusive maximum limit of the the number of repititions of this parser.
249     * When it hits the limit, it succeeds with its current output.
250     */
251    pub fn max(self, max: usize) -> Self {
252        Repeat::new(self.parser, self.reducer, self.bounds.start..max)
253    }
254    /**
255     * Sets both a minimum and maximum number of repitions for this parser to succeed.
256     */
257    pub fn bound<B: RangeBounds<usize>>(self, bounds: B) -> Self {
258        let lower = match bounds.start_bound() {
259            std::ops::Bound::Included(val) => *val,
260            //The lower bound for a range shound never be usize::MAX.
261            std::ops::Bound::Excluded(val) => {
262                if *val == usize::MAX {
263                    panic!("The lower bound for the range shouldn't be usize::MAX")
264                } else {
265                    *val + 1
266                }
267            }
268            std::ops::Bound::Unbounded => 0,
269        };
270        let upper = match bounds.end_bound() {
271            //An inclusive bound of usize::MAX makes sense, don't wrap it to 0.
272            std::ops::Bound::Included(val) => {
273                if *val == usize::MAX {
274                    *val
275                } else {
276                    *val + 1
277                }
278            }
279            std::ops::Bound::Excluded(val) => *val,
280            std::ops::Bound::Unbounded => usize::MAX,
281        };
282        Repeat::new(self.parser, self.reducer, lower..upper)
283    }
284    /**
285     * Returns the slice of the input that this parser matched. &str when parsing &str, &\[T\] when parsing  &\[T\]
286     */
287    pub fn as_input_slice(self) -> Repeat<P, ParI, ParO, ParE, InputSliceReducer, ()> {
288        Repeat::new(
289            self.parser,
290            Reducer {
291                acc: (),
292                reduce_operator: InputSliceReducer,
293            },
294            self.bounds,
295        )
296    }
297    /**
298     * By default this parser will output a vec. This method allows that to be replaced
299     * with a custom type to costruct HashMaps or other custom output types.
300     * This method takes in `acc`, the accumulator base case and `reduce_fn` the
301     * custom try reduce function. `reduce_fn` can be of the form
302     * `fn(&mut acc)->()` if it always succeeds. If if can fail, it can
303     * be of the forms `[fn(&mut acc)->Option<()>, fn(&mut acc)->bool, fn(&mut acc)->Result<(),E> ]`
304     * It can also be a custom struct that implements the TryReducer trait.
305     */
306    pub fn reduce<NewAcc: Clone, NewF>(
307        self,
308        acc: NewAcc,
309        reduce_fn: NewF,
310    ) -> Repeat<P, ParI, ParO, ParE, NewF, NewAcc> {
311        Repeat::new(
312            self.parser,
313            Reducer {
314                acc,
315                reduce_operator: reduce_fn,
316            },
317            self.bounds,
318        )
319    }
320}