rivia/core/
iter.rs

1use std::{fmt, iter::Iterator};
2
3use crate::errors::*;
4
5/// Assert that the elements of the given iterables are equal and `Panics` when when not.
6///
7/// # Examples
8/// ```
9/// use rivia::prelude::*;
10///
11/// assert_iter_eq(vec![1, 2, 3].into_iter(), vec![1, 2, 3].into_iter());
12/// ```
13pub fn assert_iter_eq<T, U>(x: T, y: U)
14where
15    T: IntoIterator,
16    U: IntoIterator,
17    T::Item: fmt::Debug + PartialEq<U::Item>,
18    U::Item: fmt::Debug,
19{
20    let mut x = x.into_iter();
21    let mut y = y.into_iter();
22    loop {
23        let (a, b) = (x.next(), y.next());
24        if a.is_none() && b.is_none() {
25            return;
26        }
27        let equal = match (&a, &b) {
28            // Compare the two items
29            (Some(a), Some(b)) => a == b,
30
31            // Different lengths
32            _ => false,
33        };
34        assert!(equal, "Iterators not equal {:?} != {:?}", a, b);
35    }
36}
37
38/// Provides extensions for the [`Iterator`] trait
39pub trait IteratorExt: Iterator {
40    /// Consume the entire iterator eagerly up until but not including the last call to
41    /// get None. Allows caller to then call next and get None.
42    ///
43    /// # Examples
44    /// ```
45    /// use rivia::prelude::*;
46    ///
47    /// assert_eq!(vec![0, 1, 2].into_iter().consume().next(), None);
48    /// ```
49    fn consume(self) -> Self
50    where
51        Self: Sized;
52
53    /// Drop the first `n` items if positive from the iterator eagerly and then return the
54    /// iterator. Drop the last `|n|` items if negative from the iterator eagerly and then
55    /// return the iterator.
56    ///
57    /// # Examples
58    /// ```
59    /// use rivia::prelude::*;
60    ///
61    /// assert_iter_eq(vec![1, 2, 3].into_iter().drop(1), vec![2, 3]);
62    /// assert_iter_eq(vec![1, 2, 3].into_iter().drop(-1), vec![1, 2]);
63    /// ```
64    fn drop(self, n: isize) -> Self
65    where
66        Self: Sized,
67        Self: DoubleEndedIterator;
68
69    /// Returns the first element of the iterator. Alias to nth(0).
70    ///
71    /// `first()` will return [`None`] if `n` is greater than or equal to the length of the
72    /// iterator.
73    ///
74    /// # Examples
75    /// ```
76    /// use rivia::prelude::*;
77    ///
78    /// assert_eq!((0..10).filter(|&x| x == 2).first().unwrap(), 2);
79    /// ```
80    fn first(self) -> Option<Self::Item>
81    where
82        Self: Sized;
83
84    /// If the iterator yields at least one element, the first element will be returned,
85    /// otherwise an error will be returned.
86    ///
87    /// # Examples
88    /// ```
89    /// use rivia::prelude::*;
90    ///
91    /// assert_eq!((0..10).filter(|&x| x == 2).first().unwrap(), 2);
92    /// ```
93    fn first_result(self) -> RvResult<Self::Item>
94    where
95        Self: Sized;
96
97    /// If the iterator yields at least one element, the last element will be returned,
98    /// otherwise an error will be returned.
99    ///
100    /// # Examples
101    /// ```
102    /// use rivia::prelude::*;
103    ///
104    /// assert_eq!((0..10).filter(|&x| x == 2).last().unwrap(), 2);
105    /// ```
106    fn last_result(self) -> RvResult<Self::Item>
107    where
108        Self: Sized;
109
110    /// If the iterator yields a single element, that element will be returned, otherwise an
111    /// error will be returned.
112    ///
113    /// # Examples
114    /// ```
115    /// use rivia::prelude::*;
116    ///
117    /// assert_eq!((0..10).filter(|&x| x == 2).single().unwrap(), 2);
118    /// ```
119    fn single(self) -> RvResult<Self::Item>
120    where
121        Self: Sized;
122
123    /// Slice returns this iterator eagerly to only iterate over the range of elements called out
124    /// by the given indices. Allows for negative notation.
125    ///
126    /// Note this operation uses count() to determine length which means cost O(n) out of the gate.
127    ///
128    /// # Examples
129    /// ```
130    /// use rivia::prelude::*;
131    ///
132    /// let mut iter = vec![0, 1, 2].into_iter().slice(0, 0);
133    /// assert_eq!(iter.next(), Some(0));
134    /// assert_eq!(iter.next(), None);
135    ///
136    /// let mut iter = vec![0, 1, 2].into_iter().slice(-1, -1);
137    /// assert_eq!(iter.next(), Some(2));
138    /// assert_eq!(iter.next(), None);
139    ///
140    /// let mut iter = vec![0, 1, 2].into_iter().slice(-2, -1);
141    /// assert_eq!(iter.next(), Some(1));
142    /// assert_eq!(iter.next(), Some(2));
143    /// assert_eq!(iter.next(), None);
144    /// ```
145    fn slice(self, left: isize, right: isize) -> Self
146    where
147        Self: Sized,
148        Self: Clone,
149        Self: DoubleEndedIterator;
150
151    /// If the iterator yields at least one element, true will be returned else false
152    ///
153    /// # Examples
154    /// ```
155    /// use rivia::prelude::*;
156    ///
157    /// assert_eq!((0..10).filter(|&x| x == 2).some(), true);
158    /// ```
159    fn some(self) -> bool
160    where
161        Self: Sized;
162}
163
164impl<T: ?Sized> IteratorExt for T
165where
166    T: Iterator,
167{
168    #[allow(clippy::all)]
169    fn consume(mut self) -> Self
170    where
171        Self: Sized,
172    {
173        let mut iter = (&mut self).peekable();
174        while let Some(_) = iter.next() {}
175        self
176    }
177
178    fn drop(mut self, n: isize) -> Self
179    where
180        Self: Sized,
181        Self: DoubleEndedIterator,
182    {
183        // Drop left
184        if n > 0 {
185            self.nth(n as usize - 1);
186        }
187
188        // Drop right
189        if n < 0 {
190            (&mut self).rev().nth(n.unsigned_abs() - 1);
191        }
192        self
193    }
194
195    fn first(mut self) -> Option<Self::Item>
196    where
197        Self: Sized,
198    {
199        self.next()
200    }
201
202    fn first_result(mut self) -> RvResult<Self::Item>
203    where
204        Self: Sized,
205    {
206        match self.next() {
207            Some(first) => Ok(first),
208            None => Err(IterError::item_not_found().into()),
209        }
210    }
211
212    fn last_result(self) -> RvResult<Self::Item>
213    where
214        Self: Sized,
215    {
216        match self.last() {
217            Some(item) => Ok(item),
218            None => Err(IterError::item_not_found().into()),
219        }
220    }
221
222    fn single(mut self) -> RvResult<Self::Item>
223    where
224        Self: Sized,
225    {
226        match self.next() {
227            Some(item) => match self.next() {
228                Some(_) => Err(IterError::multiple_items_found().into()),
229                None => Ok(item),
230            },
231            None => Err(IterError::item_not_found().into()),
232        }
233    }
234
235    fn slice(mut self, left: isize, right: isize) -> Self
236    where
237        Self: Sized,
238        Self: Clone,
239        Self: DoubleEndedIterator,
240    {
241        // Convert left to postive notation and trim
242        let (mut l, mut r): (usize, usize) = (left as usize, 0);
243        let len = (self.clone()).count() as isize;
244        if left < 0 {
245            l = (len + left) as usize;
246        }
247        if l > 0 {
248            self.nth(l - 1);
249        }
250
251        // Convert right to negative notation and trim.
252        // Offset to have inclusive behavior.
253        if right > 0 && right < len {
254            r = (right - len + 1).unsigned_abs();
255        } else if right < 0 && right.abs() <= len {
256            r = (right.abs() - 1).unsigned_abs();
257        } else if right < 0 {
258            r = len as usize;
259        }
260        if r > 0 {
261            (&mut self).rev().nth(r - 1);
262        }
263
264        // Get first or last
265        if left == 0 && right == 0 {
266            let i = len - 2;
267            if i > 0 {
268                (&mut self).rev().nth(i as usize);
269            }
270        }
271
272        self
273    }
274
275    fn some(mut self) -> bool
276    where
277        Self: Sized,
278    {
279        self.next().is_some()
280    }
281}
282
283#[cfg(test)]
284mod tests {
285    use std::ffi::OsStr;
286    use std::path::{Component, PathBuf};
287
288    use crate::core::*;
289    use crate::errors::*;
290
291    #[test]
292    fn test_slice() {
293        // Both negative
294        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(-1, -5).next(), None); // right out of bounds negatively consumes all
295        assert_iter_eq(vec![0, 1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(-4, -1)); // get all
296        assert_iter_eq(vec![0, 1, 2], vec![0, 1, 2, 3].into_iter().slice(-4, -2)); // get all but last
297        assert_iter_eq(vec![0, 1], vec![0, 1, 2, 3].into_iter().slice(-4, -3)); // get all but last 2
298        assert_iter_eq(vec![3], vec![0, 1, 2, 3].into_iter().slice(-1, -1)); // get last
299        assert_iter_eq(vec![2], vec![0, 1, 2, 3].into_iter().slice(-2, -2)); // get index 2
300        assert_iter_eq(vec![1], vec![0, 1, 2, 3].into_iter().slice(-3, -3)); // get index 1
301        assert_iter_eq(vec![0], vec![0, 1, 2, 3].into_iter().slice(-4, -4)); // get first
302        assert_iter_eq(vec![1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(-3, -1)); // get all but first
303        assert_iter_eq(vec![1, 2], vec![0, 1, 2, 3].into_iter().slice(-3, -2)); // get middle
304        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(-1, -2).next(), None); // mutually exclusive consumes everything
305
306        // Both positive
307        assert_iter_eq(vec![0, 1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(0, 4)); // right out of bounds positively gets moved in
308        assert_iter_eq(vec![0, 1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(0, 3)); // get all
309        assert_iter_eq(vec![0, 1, 2], vec![0, 1, 2, 3].into_iter().slice(0, 2)); // get all but last
310        assert_iter_eq(vec![0, 1], vec![0, 1, 2, 3].into_iter().slice(0, 1)); // get all but last 2
311        assert_iter_eq(vec![3], vec![0, 1, 2, 3].into_iter().slice(3, 3)); // get last
312        assert_iter_eq(vec![2], vec![0, 1, 2, 3].into_iter().slice(2, 2)); // get index 2
313        assert_iter_eq(vec![1], vec![0, 1, 2, 3].into_iter().slice(1, 1)); // get index 1
314        assert_iter_eq(vec![0], vec![0, 1, 2, 3].into_iter().slice(0, 0)); // get first
315        assert_iter_eq(vec![1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(1, 3)); // get all but first
316        assert_iter_eq(vec![1, 2], vec![0, 1, 2, 3].into_iter().slice(1, 2)); // get middle
317        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(3, 2).next(), None); // mutually exclusive consumes everything
318        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(4, 3).next(), None); // left out of bounds consumes everything
319
320        // Left postive and right negative
321        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(0, -5).next(), None); // right out of bounds negatively consumes all
322        assert_iter_eq(vec![0, 1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(0, -1)); // get all
323        assert_iter_eq(vec![0, 1, 2], vec![0, 1, 2, 3].into_iter().slice(0, -2)); // get all but last
324        assert_iter_eq(vec![0, 1], vec![0, 1, 2, 3].into_iter().slice(0, -3)); // get all but last 2
325        assert_iter_eq(vec![3], vec![0, 1, 2, 3].into_iter().slice(3, -1)); // get last
326        assert_iter_eq(vec![2], vec![0, 1, 2, 3].into_iter().slice(2, -2)); // get index 2
327        assert_iter_eq(vec![1], vec![0, 1, 2, 3].into_iter().slice(1, -3)); // get index 1
328        assert_iter_eq(vec![0], vec![0, 1, 2, 3].into_iter().slice(0, -4)); // get first
329        assert_iter_eq(vec![1, 2, 3], vec![0, 1, 2, 3].into_iter().slice(1, -1)); // get all but first
330        assert_iter_eq(vec![1, 2], vec![0, 1, 2, 3].into_iter().slice(1, -2)); // get middle
331        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(3, -2).next(), None); // mutually exclusive consumes everything
332        assert_eq!(vec![0, 1, 2, 3].into_iter().slice(4, -1).next(), None); // left out of bounds
333                                                                            // consumes everything
334    }
335
336    #[test]
337    fn test_consume() {
338        assert_eq!(vec![0].into_iter().nth(0), Some(0));
339        assert_eq!(vec![0, 1, 2].into_iter().consume().nth(0), None);
340    }
341
342    #[test]
343    fn test_drop() {
344        // Start
345        assert_iter_eq(vec![2, 3], vec![1, 2, 3].into_iter().drop(1));
346        assert_iter_eq(PathBuf::from("bar").components(), PathBuf::from("foo/bar").components().drop(1));
347        assert_iter_eq(PathBuf::from("bar").components(), PathBuf::from("/foo/bar").components().drop(2));
348
349        // End
350        assert_iter_eq(vec![1, 2], vec![1, 2, 3].into_iter().drop(-1));
351        assert_eq!(1, vec![1, 2, 3].into_iter().drop(-1).next().unwrap());
352        assert_iter_eq(PathBuf::from("foo").components(), PathBuf::from("foo/bar").components().drop(-1));
353        assert_iter_eq(PathBuf::from("/").components(), PathBuf::from("/foo/bar").components().drop(-2));
354    }
355
356    #[test]
357    fn test_eq() {
358        assert_iter_eq(vec![1, 2], vec![1, 2]);
359        assert!(std::panic::catch_unwind(|| assert_iter_eq(vec![1, 2], vec![1])).is_err());
360        assert!(std::panic::catch_unwind(|| assert_iter_eq(vec![1, 2], vec![1, 3])).is_err());
361        assert_iter_eq(PathBuf::from("foo/bar").components(), PathBuf::from("foo/bar").components());
362        assert!(std::panic::catch_unwind(|| assert_iter_eq(
363            PathBuf::from("foo/bar").components(),
364            PathBuf::from("bar").components()
365        ))
366        .is_err());
367    }
368
369    #[test]
370    fn test_first() {
371        assert_eq!(Component::Normal(OsStr::new("foo")), PathBuf::from("foo/bar").components().first().unwrap());
372        assert_ne!(Component::Normal(OsStr::new("bar")), PathBuf::from("foo/bar").components().first().unwrap());
373    }
374
375    #[test]
376    fn test_first_result() {
377        assert_eq!(
378            Component::Normal(OsStr::new("foo")),
379            PathBuf::from("foo/bar").components().first_result().unwrap()
380        );
381        assert_ne!(
382            Component::Normal(OsStr::new("bar")),
383            PathBuf::from("foo/bar").components().first_result().unwrap()
384        );
385    }
386
387    #[test]
388    fn test_last_result() {
389        assert_eq!(
390            Component::Normal(OsStr::new("bar")),
391            PathBuf::from("foo/bar").components().last_result().unwrap()
392        );
393        assert_ne!(
394            Component::Normal(OsStr::new("foo")),
395            PathBuf::from("foo/bar").components().last_result().unwrap()
396        );
397    }
398
399    #[test]
400    fn test_single() {
401        assert_eq!((0..10).filter(|&x| x == 2).single().unwrap(), 2);
402        assert_eq!(
403            (0..10).filter(|&x| x > 2).single().unwrap_err().downcast_ref::<IterError>(),
404            Some(&IterError::multiple_items_found())
405        );
406        assert_eq!(
407            (0..10).filter(|&x| x > 2 && x < 5).single().unwrap_err().downcast_ref::<IterError>(),
408            Some(&IterError::multiple_items_found())
409        );
410    }
411
412    #[test]
413    fn test_some() {
414        assert_eq!((0..10).filter(|&x| x == 2).some(), true);
415        assert_eq!((0..10).filter(|&x| x == 11).some(), false);
416    }
417}