pipe_chain/pipe/
repeat.rs

1use crate::{Pipe, Result as PResult};
2use fatal_error::FatalError;
3use std::{
4    convert::Infallible,
5    marker::PhantomData,
6    ops::{
7        Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo,
8        RangeToInclusive,
9    },
10};
11use tuplify::Unpack;
12
13/// Invalid repetition
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct InvalidRepetition(usize, usize);
16
17impl From<Infallible> for InvalidRepetition {
18    fn from(_: Infallible) -> Self { unreachable!() }
19}
20
21impl std::fmt::Display for InvalidRepetition {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "Invalid repetition: min: {} - max: {}", self.0, self.1)
24    }
25}
26
27impl std::error::Error for InvalidRepetition {}
28
29/// Represents a range or a fixed number
30///
31/// the upper limit is optionally defined
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct Repetition {
34    min: usize,
35    max: Option<usize>,
36}
37
38impl Repetition {
39    /// Creates a new repetition
40    ///
41    /// `max` is inclusive
42    ///
43    /// returns an error if `min` > `max`
44    pub fn range(min: usize, max: Option<usize>) -> Result<Self, InvalidRepetition> {
45        if max.map_or(true, |x| x >= min) {
46            Ok(Repetition { min, max })
47        } else {
48            Err(InvalidRepetition(min, max.unwrap()))
49        }
50    }
51
52    /// Creates a new repetition with a fixed number
53    pub fn exact(n: usize) -> Result<Self, InvalidRepetition> {
54        Ok(Repetition { min: n, max: Some(n) })
55    }
56
57    /// Return true if `nb` < `min`
58    pub fn needs_more(&self, nb: usize) -> bool { nb < self.min }
59
60    /// Return true if `nb` == `max`
61    pub fn is_max(&self, nb: usize) -> bool { self.max.map_or(false, |x| nb == x) }
62
63    /// Error handling
64    ///
65    /// Calls the provided function `f` with `min`, `max`, `nb` if `nb` is outside of the repetition boundaries
66    pub fn map_err<E>(
67        &self, nb: usize, f: impl FnOnce(usize, Option<usize>, usize) -> E,
68    ) -> Result<(), E> {
69        if nb >= self.min && self.max.map_or(true, |x| nb <= x) {
70            Ok(())
71        } else {
72            Err(f(self.min, self.max, nb))
73        }
74    }
75
76    /// Returns the minimum number of repetitions needed after `nb` repetitions
77    pub fn min_needed(&self, nb: usize) -> usize { self.min.saturating_sub(nb) }
78}
79
80impl TryFrom<usize> for Repetition {
81    type Error = InvalidRepetition;
82
83    fn try_from(value: usize) -> Result<Self, Self::Error> { Self::exact(value) }
84}
85
86impl From<RangeFrom<usize>> for Repetition {
87    fn from(value: RangeFrom<usize>) -> Self {
88        Repetition { min: value.start, max: None }
89    }
90}
91
92impl From<RangeFull> for Repetition {
93    fn from(_: RangeFull) -> Self { Repetition { min: 0, max: None } }
94}
95
96impl TryFrom<Range<usize>> for Repetition {
97    type Error = InvalidRepetition;
98
99    fn try_from(value: Range<usize>) -> Result<Self, Self::Error> {
100        Repetition::range(
101            value.start,
102            match value.end_bound() {
103                Bound::Included(x) => Some(*x),
104                Bound::Excluded(x) => Some(x.saturating_sub(1)),
105                Bound::Unbounded => None,
106            },
107        )
108    }
109}
110
111impl TryFrom<RangeInclusive<usize>> for Repetition {
112    type Error = InvalidRepetition;
113
114    fn try_from(value: RangeInclusive<usize>) -> Result<Self, Self::Error> {
115        Repetition::range(*value.start(), Some(*value.end()))
116    }
117}
118
119impl TryFrom<RangeTo<usize>> for Repetition {
120    type Error = InvalidRepetition;
121
122    fn try_from(value: RangeTo<usize>) -> Result<Self, Self::Error> {
123        Repetition::range(0, Some(value.end.saturating_sub(1)))
124    }
125}
126
127impl TryFrom<RangeToInclusive<usize>> for Repetition {
128    type Error = InvalidRepetition;
129
130    fn try_from(value: RangeToInclusive<usize>) -> Result<Self, Self::Error> {
131        Repetition::range(0, Some(value.end))
132    }
133}
134
135/// Combinator that makes repetitions
136pub trait RepeatExt<I, O, E> {
137    /// Repeats this pipe.
138    ///
139    /// The repetition can be a fixed number or a range
140    fn repeat<R>(self, r: R) -> RepeatPipe<Self, O>
141    where
142        R: TryInto<Repetition>,
143        R::Error: std::error::Error,
144        Self: Pipe<I, O, E> + Sized,
145    {
146        RepeatPipe::new(self, r.try_into().unwrap())
147    }
148}
149
150impl<I, O, E, P> RepeatExt<I, O, E> for P where P: Pipe<I, O, E> {}
151
152/// [RepeatExt::repeat] implementation
153pub struct RepeatPipe<P, O> {
154    p: P,
155    r: Repetition,
156    o: PhantomData<O>,
157}
158
159impl<P, O> RepeatPipe<P, O> {
160    fn new(p: P, r: Repetition) -> Self { Self { p, r, o: PhantomData } }
161}
162
163impl<I, O, E, P> Pipe<I, (Vec<O::Output>,), E> for RepeatPipe<P, O>
164where
165    I: Clone,
166    O: Unpack,
167    P: Pipe<I, O, E> + Sized,
168{
169    fn apply(&mut self, mut input: I) -> PResult<I, (Vec<O::Output>,), E> {
170        let mut r = Vec::new();
171        for x in 0.. {
172            match self.p.apply(input.clone()) {
173                Ok((i, o)) => {
174                    input = i;
175                    r.push(o.unpack());
176                }
177                Err(e @ FatalError::Error(_)) => {
178                    if self.r.needs_more(x) {
179                        return Err(e);
180                    } else {
181                        break;
182                    }
183                }
184                Err(x) => return Err(x),
185            }
186            if self.r.is_max(x) {
187                break;
188            }
189        }
190        Ok((input, (r,)))
191    }
192}