Jakub Kotur | a425e55 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 1 | |
| 2 | use std::iter::IntoIterator; |
Joel Galenson | 6f79871 | 2021-04-01 17:03:06 -0700 | [diff] [blame] | 3 | use alloc::rc::Rc; |
Jakub Kotur | a425e55 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 4 | use std::cell::RefCell; |
| 5 | |
| 6 | /// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait. |
| 7 | #[derive(Debug)] |
| 8 | pub struct RcIter<I> { |
| 9 | /// The boxed iterator. |
| 10 | pub rciter: Rc<RefCell<I>>, |
| 11 | } |
| 12 | |
| 13 | /// Return an iterator inside a `Rc<RefCell<_>>` wrapper. |
| 14 | /// |
| 15 | /// The returned `RcIter` can be cloned, and each clone will refer back to the |
| 16 | /// same original iterator. |
| 17 | /// |
| 18 | /// `RcIter` allows doing interesting things like using `.zip()` on an iterator with |
| 19 | /// itself, at the cost of runtime borrow checking which may have a performance |
| 20 | /// penalty. |
| 21 | /// |
| 22 | /// Iterator element type is `Self::Item`. |
| 23 | /// |
| 24 | /// ``` |
| 25 | /// use itertools::rciter; |
| 26 | /// use itertools::zip; |
| 27 | /// |
| 28 | /// // In this example a range iterator is created and we iterate it using |
| 29 | /// // three separate handles (two of them given to zip). |
| 30 | /// // We also use the IntoIterator implementation for `&RcIter`. |
| 31 | /// |
| 32 | /// let mut iter = rciter(0..9); |
| 33 | /// let mut z = zip(&iter, &iter); |
| 34 | /// |
| 35 | /// assert_eq!(z.next(), Some((0, 1))); |
| 36 | /// assert_eq!(z.next(), Some((2, 3))); |
| 37 | /// assert_eq!(z.next(), Some((4, 5))); |
| 38 | /// assert_eq!(iter.next(), Some(6)); |
| 39 | /// assert_eq!(z.next(), Some((7, 8))); |
| 40 | /// assert_eq!(z.next(), None); |
| 41 | /// ``` |
| 42 | /// |
| 43 | /// **Panics** in iterator methods if a borrow error is encountered in the |
| 44 | /// iterator methods. It can only happen if the `RcIter` is reentered in |
| 45 | /// `.next()`, i.e. if it somehow participates in an “iterator knot” |
| 46 | /// where it is an adaptor of itself. |
| 47 | pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter> |
| 48 | where I: IntoIterator |
| 49 | { |
| 50 | RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) } |
| 51 | } |
| 52 | |
| 53 | impl<I> Clone for RcIter<I> { |
| 54 | #[inline] |
| 55 | clone_fields!(rciter); |
| 56 | } |
| 57 | |
| 58 | impl<A, I> Iterator for RcIter<I> |
| 59 | where I: Iterator<Item = A> |
| 60 | { |
| 61 | type Item = A; |
| 62 | #[inline] |
Joel Galenson | 6f79871 | 2021-04-01 17:03:06 -0700 | [diff] [blame] | 63 | fn next(&mut self) -> Option<Self::Item> { |
Jakub Kotur | a425e55 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 64 | self.rciter.borrow_mut().next() |
| 65 | } |
| 66 | |
| 67 | #[inline] |
| 68 | fn size_hint(&self) -> (usize, Option<usize>) { |
| 69 | // To work sanely with other API that assume they own an iterator, |
| 70 | // so it can't change in other places, we can't guarantee as much |
| 71 | // in our size_hint. Other clones may drain values under our feet. |
Joel Galenson | 6f79871 | 2021-04-01 17:03:06 -0700 | [diff] [blame] | 72 | (0, self.rciter.borrow().size_hint().1) |
Jakub Kotur | a425e55 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 73 | } |
| 74 | } |
| 75 | |
| 76 | impl<I> DoubleEndedIterator for RcIter<I> |
| 77 | where I: DoubleEndedIterator |
| 78 | { |
| 79 | #[inline] |
Joel Galenson | 6f79871 | 2021-04-01 17:03:06 -0700 | [diff] [blame] | 80 | fn next_back(&mut self) -> Option<Self::Item> { |
Jakub Kotur | a425e55 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 81 | self.rciter.borrow_mut().next_back() |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | /// Return an iterator from `&RcIter<I>` (by simply cloning it). |
| 86 | impl<'a, I> IntoIterator for &'a RcIter<I> |
| 87 | where I: Iterator |
| 88 | { |
| 89 | type Item = I::Item; |
| 90 | type IntoIter = RcIter<I>; |
| 91 | |
| 92 | fn into_iter(self) -> RcIter<I> { |
| 93 | self.clone() |
| 94 | } |
| 95 | } |