stable_step/
lib.rs

1//! Stable Step trait
2//!
3//! Step is used to create ranges over values, in the standard library, this is implemented for
4//! numbers and can be used with the following syntax: `1..3`. Since we can't hook into the language
5//! like this, two functions are provided:
6//! - [`range`]
7//! - [`range_inclusive`]
8//!
9//! These can be used to create ranges over types that implement Step.
10//! ```rust
11//! use stable_step::{Step, StepExt};
12//!
13//! #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
14//! enum MyEnum {
15//!     A,
16//!     B,
17//!     C,
18//!     D,
19//!     E,
20//!     F,
21//! }
22//!
23//! impl Step for MyEnum {
24//!     const MIN: Self = Self::A;
25//!     const MAX: Self = Self::F;
26//!
27//!     fn next(&self) -> Option<Self>
28//!     where
29//!         Self: Sized,
30//!     {
31//!         match self {
32//!             Self::A => Some(Self::B),
33//!             Self::B => Some(Self::C),
34//!             Self::C => Some(Self::D),
35//!             Self::D => Some(Self::E),
36//!             Self::E => Some(Self::F),
37//!             Self::F => None,
38//!         }
39//!     }
40//!
41//!     fn prev(&self) -> Option<Self>
42//!     where
43//!         Self: Sized,
44//!     {
45//!         match self {
46//!             Self::A => None,
47//!             Self::B => Some(Self::A),
48//!             Self::C => Some(Self::B),
49//!             Self::D => Some(Self::C),
50//!             Self::E => Some(Self::D),
51//!             Self::F => Some(Self::E),
52//!         }
53//!     }
54//! }
55//!
56//! println!("All");
57//! for value in MyEnum::iter() {
58//!     println!("{:?}", value);
59//! }
60//!
61//! println!("Subset");
62//! for value in MyEnum::B.iter_to(MyEnum::E) {
63//!     println!("{:?}", value);
64//! }
65//!
66//! println!("Reversed");
67//! for value in MyEnum::B.iter_to_inclusive(MyEnum::E).rev() {
68//!     println!("{:?}", value);
69//! }
70//! ```
71
72use std::iter::FusedIterator;
73
74#[cfg(feature = "derive")]
75pub use stable_step_derive::Step;
76
77/// Step trait, used as a base for creating iterators
78pub trait Step: PartialOrd {
79    /// Smallest value of Self
80    const MIN: Self;
81
82    /// Largest value of Self
83    const MAX: Self;
84
85    /// Produce the next smallest value of Self
86    fn next(&self) -> Option<Self>
87    where
88        Self: Sized;
89
90    /// Produce the next largest value of Self
91    fn prev(&self) -> Option<Self>
92    where
93        Self: Sized;
94}
95
96/// Provide helper methods on types implementing Step
97pub trait StepExt: Step {
98    /// Produce an iterator over Self's full range
99    fn iter() -> RangeIter<Self>
100    where
101        Self: Sized,
102    {
103        range(None, None)
104    }
105
106    /// Iterate from Self to `to`, non-inclusive
107    fn iter_to(self, to: Self) -> RangeIter<Self>
108    where
109        Self: Sized,
110    {
111        range(Some(self), Some(to))
112    }
113
114    /// Iterate from Self to `to`, inclusive
115    fn iter_to_inclusive(self, to: Self) -> RangeIter<Self>
116    where
117        Self: Sized,
118    {
119        range_inclusive(Some(self), Some(to))
120    }
121}
122
123impl<S> StepExt for S where S: Step {}
124
125/// Iterator type for iterating over Steps
126pub struct RangeIter<S> {
127    lower: Option<S>,
128    upper: Option<S>,
129}
130
131/// Produce an iterator from `from` to `to`, inclusive of `to`
132pub fn range_inclusive<S: Step>(from: Option<S>, to: Option<S>) -> RangeIter<S> {
133    let from = match from {
134        Some(lower) => lower,
135        None => S::MIN,
136    };
137
138    let to = match to {
139        Some(upper) => upper,
140        None => S::MAX,
141    };
142
143    RangeIter {
144        lower: Some(from),
145        upper: Some(to),
146    }
147}
148
149/// Produce an iterator from `from` to `to`
150pub fn range<S: Step>(from: Option<S>, to: Option<S>) -> RangeIter<S> {
151    let to = to.and_then(|to| to.prev());
152
153    range_inclusive(from, to)
154}
155
156impl<S> Iterator for RangeIter<S>
157where
158    S: Step,
159{
160    type Item = S;
161
162    fn next(&mut self) -> Option<Self::Item> {
163        let current = self.lower.take()?;
164
165        let upper = self.upper.as_ref()?;
166
167        if &current > upper {
168            return None;
169        }
170
171        self.lower = current.next();
172
173        Some(current)
174    }
175}
176
177impl<S> DoubleEndedIterator for RangeIter<S>
178where
179    S: Step,
180{
181    fn next_back(&mut self) -> Option<Self::Item> {
182        let current = self.upper.take()?;
183
184        let lower = self.lower.as_ref()?;
185
186        if &current < lower {
187            return None;
188        }
189
190        self.upper = current.prev();
191
192        Some(current)
193    }
194}
195
196impl<S> FusedIterator for RangeIter<S> where S: Step {}
197
198#[cfg(test)]
199mod tests {
200    use super::{range, range_inclusive, Step};
201
202    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
203    enum Test {
204        One,
205        Two,
206        Three,
207        Four,
208    }
209
210    impl Step for Test {
211        const MIN: Self = Self::One;
212        const MAX: Self = Self::Four;
213
214        fn next(&self) -> Option<Self>
215        where
216            Self: Sized,
217        {
218            match self {
219                Self::One => Some(Self::Two),
220                Self::Two => Some(Self::Three),
221                Self::Three => Some(Self::Four),
222                Self::Four => None,
223            }
224        }
225
226        fn prev(&self) -> Option<Self>
227        where
228            Self: Sized,
229        {
230            match self {
231                Self::One => None,
232                Self::Two => Some(Self::One),
233                Self::Three => Some(Self::Two),
234                Self::Four => Some(Self::Three),
235            }
236        }
237    }
238
239    #[test]
240    fn range_none_none() {
241        let v: Vec<Test> = range(None, None).collect();
242
243        assert_eq!(v, vec![Test::One, Test::Two, Test::Three, Test::Four]);
244    }
245
246    #[test]
247    fn range_reverse_none_none() {
248        let v: Vec<Test> = range(None, None).rev().collect();
249
250        assert_eq!(v, vec![Test::Four, Test::Three, Test::Two, Test::One]);
251    }
252
253    #[test]
254    fn range_upper() {
255        let v: Vec<Test> = range(None, Some(Test::Four)).collect();
256
257        assert_eq!(v, vec![Test::One, Test::Two, Test::Three]);
258    }
259
260    #[test]
261    fn range_reverse_upper() {
262        let v: Vec<Test> = range(None, Some(Test::Four)).rev().collect();
263
264        assert_eq!(v, vec![Test::Three, Test::Two, Test::One]);
265    }
266
267    #[test]
268    fn range_lower() {
269        let v: Vec<Test> = range(Some(Test::Two), None).collect();
270
271        assert_eq!(v, vec![Test::Two, Test::Three, Test::Four]);
272    }
273
274    #[test]
275    fn range_reverse_lower() {
276        let v: Vec<Test> = range(Some(Test::Two), None).rev().collect();
277
278        assert_eq!(v, vec![Test::Four, Test::Three, Test::Two]);
279    }
280
281    #[test]
282    fn range_upper_lower() {
283        let v: Vec<Test> = range(Some(Test::Two), Some(Test::Four)).collect();
284
285        assert_eq!(v, vec![Test::Two, Test::Three]);
286    }
287
288    #[test]
289    fn range_reverse_upper_lower() {
290        let v: Vec<Test> = range(Some(Test::Two), Some(Test::Four)).rev().collect();
291
292        assert_eq!(v, vec![Test::Three, Test::Two]);
293    }
294
295    #[test]
296    fn range_inclusive_none_none() {
297        let v: Vec<Test> = range_inclusive(None, None).collect();
298
299        assert_eq!(v, vec![Test::One, Test::Two, Test::Three, Test::Four]);
300    }
301
302    #[test]
303    fn range_reverse_inclusive_none_none() {
304        let v: Vec<Test> = range_inclusive(None, None).rev().collect();
305
306        assert_eq!(v, vec![Test::Four, Test::Three, Test::Two, Test::One]);
307    }
308
309    #[test]
310    fn range_inclusive_upper() {
311        let v: Vec<Test> = range_inclusive(None, Some(Test::Three)).collect();
312
313        assert_eq!(v, vec![Test::One, Test::Two, Test::Three]);
314    }
315
316    #[test]
317    fn range_reverse_inclusive_upper() {
318        let v: Vec<Test> = range_inclusive(None, Some(Test::Three)).rev().collect();
319
320        assert_eq!(v, vec![Test::Three, Test::Two, Test::One]);
321    }
322
323    #[test]
324    fn range_inclusive_lower() {
325        let v: Vec<Test> = range_inclusive(Some(Test::Two), None).collect();
326
327        assert_eq!(v, vec![Test::Two, Test::Three, Test::Four]);
328    }
329
330    #[test]
331    fn range_reverse_inclusive_lower() {
332        let v: Vec<Test> = range_inclusive(Some(Test::Two), None).rev().collect();
333
334        assert_eq!(v, vec![Test::Four, Test::Three, Test::Two]);
335    }
336
337    #[test]
338    fn range_inclusive_upper_lower() {
339        let v: Vec<Test> = range_inclusive(Some(Test::Two), Some(Test::Three)).collect();
340
341        assert_eq!(v, vec![Test::Two, Test::Three]);
342    }
343
344    #[test]
345    fn range_reverse_inclusive_upper_lower() {
346        let v: Vec<Test> = range_inclusive(Some(Test::Two), Some(Test::Three))
347            .rev()
348            .collect();
349
350        assert_eq!(v, vec![Test::Three, Test::Two]);
351    }
352}