a_range/
lib.rs

1//! Create ranges in a very explicit manner
2//!
3//! Start with the [`from()`] function and build up a range using [`From::up_to`] or
4//! [`From::down_to`].
5//!
6//! # Examples
7//!
8//! ```rust
9//! extern crate a_range;
10//!
11//! let x = a_range::from(5).up_to(7);
12//! assert_eq!(x.to_vec(), vec![5, 6, 7]);
13//!
14//! let x = a_range::from(3).down_to(1);
15//! assert_eq!(x.to_vec(), vec![3, 2, 1]);
16//! ```
17
18#![warn(missing_docs)]
19
20extern crate num_traits;
21
22use num_traits::One;
23use std::iter::FromIterator;
24use std::ops::{AddAssign, SubAssign};
25
26/// Start constructing a new [Range].
27///
28/// # Examples
29///
30/// ```rust
31/// extern crate a_range;
32///
33/// let start = a_range::from(42);
34/// let range = start.up_to(48);
35///
36/// assert_eq!(range.to_vec(), vec![42, 43, 44, 45, 46, 47, 48]);
37/// ```
38pub fn from<Idx>(i: Idx) -> From<Idx> {
39    From { from: i }
40}
41
42/// Constructed using [`from()`]
43///
44/// The the methods provided for this type to build a [Range].
45#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
46pub struct From<Idx> {
47    from: Idx,
48}
49
50impl<Idx> From<Idx> {
51    /// Construct a [Range] that counts up to the given item.
52    pub fn up_to(self, x: Idx) -> Range<Idx, Upwards> {
53        Range {
54            from: self.from,
55            to: x,
56            direction: Upwards,
57        }
58    }
59
60    /// Construct a [Range] that counts down to the given item.
61    pub fn down_to(self, x: Idx) -> Range<Idx, Downwards> {
62        Range {
63            from: self.from,
64            to: x,
65            direction: Downwards,
66        }
67    }
68}
69
70/// A range
71///
72/// This is basically a start, and end, an a direction.
73///
74/// The index type can be any type, but to get a useful range, you need to supply something that
75/// implements some common traits, like [Clone], and [PartialEq]; but also [One] (the identity
76/// element used) as well as [AddAssign] and [SubAssign] (to work increment/decrement the index).
77#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
78pub struct Range<Idx, Direction> {
79    direction: Direction,
80    from: Idx,
81    to: Idx,
82}
83
84#[doc(hidden)]
85#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
86pub struct Upwards;
87
88#[doc(hidden)]
89#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
90pub struct Downwards;
91
92/// Range counting up
93impl<Idx> Range<Idx, Upwards>
94where
95    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
96{
97    /// Collect range into a container
98    ///
99    /// Works for any container type that implements [`FromIterator`].
100    pub fn collect<B>(self) -> B
101    where
102        B: FromIterator<Idx>,
103    {
104        self.into_iter().collect()
105    }
106
107    /// Turn range into a [Vec]
108    pub fn to_vec(&self) -> Vec<Idx> {
109        self.clone().into_iter().collect()
110    }
111}
112
113/// Range counting down
114impl<Idx> Range<Idx, Downwards>
115where
116    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
117{
118    /// Collect range into a container
119    ///
120    /// Works for any container type that implements [`FromIterator`].
121    pub fn collect<B>(self) -> B
122    where
123        B: FromIterator<Idx>,
124    {
125        self.into_iter().collect()
126    }
127
128    /// Turn range into a [Vec]
129    pub fn to_vec(&self) -> Vec<Idx> {
130        self.clone().into_iter().collect()
131    }
132}
133
134impl<Idx> IntoIterator for Range<Idx, Upwards>
135where
136    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
137{
138    type Item = Idx;
139    type IntoIter = RangeIter<Idx, Upwards>;
140
141    fn into_iter(self) -> Self::IntoIter {
142        RangeIter {
143            current: self.from,
144            limit: self.to,
145            direction: self.direction,
146            init: false,
147        }
148    }
149}
150
151impl<Idx> IntoIterator for Range<Idx, Downwards>
152where
153    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
154{
155    type Item = Idx;
156    type IntoIter = RangeIter<Idx, Downwards>;
157
158    fn into_iter(self) -> Self::IntoIter {
159        RangeIter {
160            current: self.from,
161            limit: self.to,
162            direction: self.direction,
163            init: false,
164        }
165    }
166}
167
168/// Iterator over a range
169pub struct RangeIter<Idx, Direction> {
170    current: Idx,
171    limit: Idx,
172    #[allow(unused)]
173    direction: Direction,
174    init: bool,
175}
176
177impl<Idx> Iterator for RangeIter<Idx, Upwards>
178where
179    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
180{
181    type Item = Idx;
182
183    fn next(&mut self) -> Option<Self::Item> {
184        if !self.init {
185            self.init = true;
186
187            return Some(self.current.clone());
188        }
189
190        if self.current == self.limit {
191            return None;
192        }
193
194        self.current += Idx::one();
195
196        Some(self.current.clone())
197    }
198}
199
200impl<Idx> Iterator for RangeIter<Idx, Downwards>
201where
202    Idx: Clone + PartialEq + One + AddAssign + SubAssign,
203{
204    type Item = Idx;
205
206    fn next(&mut self) -> Option<Self::Item> {
207        if !self.init {
208            self.init = true;
209
210            return Some(self.current.clone());
211        }
212
213        if self.current == self.limit {
214            return None;
215        }
216
217        self.current -= Idx::one();
218
219        Some(self.current.clone())
220    }
221}
222
223#[test]
224fn range_collect() {
225    let x: Vec<i32> = from(10).up_to(14).into_iter().take(10).collect();
226    assert_eq!(x, vec![10, 11, 12, 13, 14]);
227}
228
229#[test]
230fn rev_range_collect() {
231    let x: Vec<i32> = from(14).down_to(10).into_iter().take(10).collect();
232    assert_eq!(x, vec![14, 13, 12, 11, 10]);
233}