use std::iter::{FusedIterator, IntoIterator}; use alloc::rc::Rc; use std::cell::RefCell; /// A wrapper for `Rc>`, that implements the `Iterator` trait. #[derive(Debug)] pub struct RcIter { /// The boxed iterator. pub rciter: Rc>, } /// Return an iterator inside a `Rc>` wrapper. /// /// The returned `RcIter` can be cloned, and each clone will refer back to the /// same original iterator. /// /// `RcIter` allows doing interesting things like using `.zip()` on an iterator with /// itself, at the cost of runtime borrow checking which may have a performance /// penalty. /// /// Iterator element type is `Self::Item`. /// /// ``` /// use itertools::rciter; /// use itertools::zip; /// /// // In this example a range iterator is created and we iterate it using /// // three separate handles (two of them given to zip). /// // We also use the IntoIterator implementation for `&RcIter`. /// /// let mut iter = rciter(0..9); /// let mut z = zip(&iter, &iter); /// /// assert_eq!(z.next(), Some((0, 1))); /// assert_eq!(z.next(), Some((2, 3))); /// assert_eq!(z.next(), Some((4, 5))); /// assert_eq!(iter.next(), Some(6)); /// assert_eq!(z.next(), Some((7, 8))); /// assert_eq!(z.next(), None); /// ``` /// /// **Panics** in iterator methods if a borrow error is encountered in the /// iterator methods. It can only happen if the `RcIter` is reentered in /// `.next()`, i.e. if it somehow participates in an “iterator knot” /// where it is an adaptor of itself. pub fn rciter(iterable: I) -> RcIter where I: IntoIterator { RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) } } impl Clone for RcIter { clone_fields!(rciter); } impl Iterator for RcIter where I: Iterator { type Item = A; #[inline] fn next(&mut self) -> Option { self.rciter.borrow_mut().next() } #[inline] fn size_hint(&self) -> (usize, Option) { // To work sanely with other API that assume they own an iterator, // so it can't change in other places, we can't guarantee as much // in our size_hint. Other clones may drain values under our feet. (0, self.rciter.borrow().size_hint().1) } } impl DoubleEndedIterator for RcIter where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option { self.rciter.borrow_mut().next_back() } } /// Return an iterator from `&RcIter` (by simply cloning it). impl<'a, I> IntoIterator for &'a RcIter where I: Iterator { type Item = I::Item; type IntoIter = RcIter; fn into_iter(self) -> RcIter { self.clone() } } impl FusedIterator for RcIter where I: FusedIterator {}