pub trait TransposableIterator: Iterator { fn transpose(self) -> Transpose where Self: Iterator + Clone + Sized, C: IntoIterator, J: ExactSizeIterator { Transpose::new(self) } } impl TransposableIterator for I where I: Iterator {} #[derive(Clone)] pub struct Transpose { loc: ::std::ops::Range, iter: I, } impl Transpose where I: Iterator + Clone, C: IntoIterator, J: ExactSizeIterator { fn new(base: I) -> Transpose { let longest = base.clone() .fold(0, |len, row| ::std::cmp::max(len, row.into_iter().len())); Transpose { loc: 0..longest, iter: base, } } } impl Iterator for Transpose where I: Clone { type Item = TransposeInner; #[inline] fn next(&mut self) -> Option> { self.loc.next().map(|idx| { TransposeInner { iter: self.iter.clone(), col: idx, } }) } fn size_hint(&self) -> (usize, Option) { (self.loc.end, Some(self.loc.end)) } } impl ExactSizeIterator for Transpose where I: Clone {} impl DoubleEndedIterator for Transpose where I: Clone { fn next_back(&mut self) -> Option> { self.loc.next_back().map(|idx| { TransposeInner { iter: self.iter.clone(), col: idx, } }) } } #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[derive(Clone)] pub struct TransposeInner { iter: I, col: usize, } impl Iterator for TransposeInner where I: Iterator, J: IntoIterator { type Item = T; #[inline] fn next(&mut self) -> Option { self.iter.next().and_then(|row| row.into_iter().nth(self.col)) } } // TODO: ExactSizeIterator and DoubleEndedIterator for TransposeInner