Files
vrtue/src/transpose.rs

90 lines
1.9 KiB
Rust

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