use std::iter::{Fuse,Peekable, FusedIterator}; /// An iterator adaptor that wraps each element in an [`Position`]. /// /// Iterator element type is `(Position, I::Item)`. /// /// See [`.with_position()`](crate::Itertools::with_position) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct WithPosition where I: Iterator, { handled_first: bool, peekable: Peekable>, } impl Clone for WithPosition where I: Clone + Iterator, I::Item: Clone, { clone_fields!(handled_first, peekable); } /// Create a new `WithPosition` iterator. pub fn with_position(iter: I) -> WithPosition where I: Iterator, { WithPosition { handled_first: false, peekable: iter.fuse().peekable(), } } /// The first component of the value yielded by `WithPosition`. /// Indicates the position of this element in the iterator results. /// /// See [`.with_position()`](crate::Itertools::with_position) for more information. #[derive(Copy, Clone, Debug, PartialEq)] pub enum Position { /// This is the first element. First, /// This is neither the first nor the last element. Middle, /// This is the last element. Last, /// This is the only element. Only, } impl Iterator for WithPosition { type Item = (Position, I::Item); fn next(&mut self) -> Option { match self.peekable.next() { Some(item) => { if !self.handled_first { // Haven't seen the first item yet, and there is one to give. self.handled_first = true; // Peek to see if this is also the last item, // in which case tag it as `Only`. match self.peekable.peek() { Some(_) => Some((Position::First, item)), None => Some((Position::Only, item)), } } else { // Have seen the first item, and there's something left. // Peek to see if this is the last item. match self.peekable.peek() { Some(_) => Some((Position::Middle, item)), None => Some((Position::Last, item)), } } } // Iterator is finished. None => None, } } fn size_hint(&self) -> (usize, Option) { self.peekable.size_hint() } } impl ExactSizeIterator for WithPosition where I: ExactSizeIterator, { } impl FusedIterator for WithPosition {}