| 
 | 1 | +use super::size_hint;  | 
 | 2 | +use std::cmp::Ordering;  | 
 | 3 | +use std::fmt;  | 
 | 4 | + | 
 | 5 | +/// An iterator which iterates two other iterators simultaneously  | 
 | 6 | +/// always returning the first and last elements of both iterators by using  | 
 | 7 | +/// cloning to extend the length of the shortest iterator.  | 
 | 8 | +///  | 
 | 9 | +/// See [`.zip_stretch()`](crate::Itertools::zip_stretch) for more information.  | 
 | 10 | +#[derive(Clone)]  | 
 | 11 | +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]  | 
 | 12 | +pub struct ZipStretch<I: ExactSizeIterator, J: ExactSizeIterator>  | 
 | 13 | +where  | 
 | 14 | +    <I as Iterator>::Item: Clone,  | 
 | 15 | +    <J as Iterator>::Item: Clone,  | 
 | 16 | +{  | 
 | 17 | +    a: I,  | 
 | 18 | +    b: J,  | 
 | 19 | +    a_delta: f32,  | 
 | 20 | +    b_delta: f32,  | 
 | 21 | +    a_index: f32,  | 
 | 22 | +    b_index: f32,  | 
 | 23 | +    a_dupe: Option<<I as Iterator>::Item>,  | 
 | 24 | +    b_dupe: Option<<J as Iterator>::Item>,  | 
 | 25 | +}  | 
 | 26 | + | 
 | 27 | +impl<I: ExactSizeIterator + fmt::Debug, J: ExactSizeIterator + fmt::Debug> fmt::Debug  | 
 | 28 | +    for ZipStretch<I, J>  | 
 | 29 | +where  | 
 | 30 | +    <I as Iterator>::Item: Clone,  | 
 | 31 | +    <J as Iterator>::Item: Clone,  | 
 | 32 | +{  | 
 | 33 | +    debug_fmt_fields!(ZipStretch, a, b, a_delta, b_delta, a_index, b_index);  | 
 | 34 | +}  | 
 | 35 | + | 
 | 36 | +/// Zips two iterators cloning elements to extend the length of the shortest iterator to  | 
 | 37 | +/// ensure it fully consumes both iterators.  | 
 | 38 | +///  | 
 | 39 | +/// [`IntoIterator`] enabled version of [`Itertools::zip_stretch`](crate::Itertools::zip_stretch).  | 
 | 40 | +pub fn zip_stretch<I, J>(i: I, j: J) -> ZipStretch<I::IntoIter, J::IntoIter>  | 
 | 41 | +where  | 
 | 42 | +    I: IntoIterator,  | 
 | 43 | +    J: IntoIterator,  | 
 | 44 | +    <I as IntoIterator>::IntoIter: ExactSizeIterator,  | 
 | 45 | +    <J as IntoIterator>::IntoIter: ExactSizeIterator,  | 
 | 46 | +    <<I as IntoIterator>::IntoIter as IntoIterator>::Item: Clone,  | 
 | 47 | +    <<J as IntoIterator>::IntoIter as IntoIterator>::Item: Clone,  | 
 | 48 | +{  | 
 | 49 | +    use std::iter::ExactSizeIterator;  | 
 | 50 | +    let (a, b) = (i.into_iter(), j.into_iter());  | 
 | 51 | +    let (a_delta, b_delta) = match a.len().cmp(&b.len()) {  | 
 | 52 | +        Ordering::Equal => (1f32, 1f32),  | 
 | 53 | +        Ordering::Less => (a.len() as f32 / b.len() as f32, 1f32),  | 
 | 54 | +        Ordering::Greater => (1f32, b.len() as f32 / a.len() as f32),  | 
 | 55 | +    };  | 
 | 56 | +    debug_assert!(a_delta <= 1f32);  | 
 | 57 | +    debug_assert!(b_delta <= 1f32);  | 
 | 58 | +    ZipStretch {  | 
 | 59 | +        a,  | 
 | 60 | +        b,  | 
 | 61 | +        a_delta,  | 
 | 62 | +        b_delta,  | 
 | 63 | +        a_index: 0f32,  | 
 | 64 | +        b_index: 0f32,  | 
 | 65 | +        a_dupe: None,  | 
 | 66 | +        b_dupe: None,  | 
 | 67 | +    }  | 
 | 68 | +}  | 
 | 69 | + | 
 | 70 | +impl<I, J> Iterator for ZipStretch<I, J>  | 
 | 71 | +where  | 
 | 72 | +    I: ExactSizeIterator,  | 
 | 73 | +    J: ExactSizeIterator,  | 
 | 74 | +    <I as Iterator>::Item: Clone,  | 
 | 75 | +    <J as Iterator>::Item: Clone,  | 
 | 76 | +{  | 
 | 77 | +    type Item = (I::Item, J::Item);  | 
 | 78 | + | 
 | 79 | +    fn next(&mut self) -> Option<Self::Item> {  | 
 | 80 | +        if self.a_index.fract() < self.a_delta {  | 
 | 81 | +            self.a_dupe = self.a.next();  | 
 | 82 | +        }  | 
 | 83 | +        self.a_index += self.a_delta;  | 
 | 84 | + | 
 | 85 | +        if self.b_index.fract() < self.b_delta {  | 
 | 86 | +            self.b_dupe = self.b.next();  | 
 | 87 | +        }  | 
 | 88 | +        self.b_index += self.b_delta;  | 
 | 89 | + | 
 | 90 | +        self.a_dupe.clone().zip(self.b_dupe.clone())  | 
 | 91 | +    }  | 
 | 92 | + | 
 | 93 | +    fn size_hint(&self) -> (usize, Option<usize>) {  | 
 | 94 | +        size_hint::min(self.a.size_hint(), self.b.size_hint())  | 
 | 95 | +    }  | 
 | 96 | +}  | 
 | 97 | + | 
 | 98 | +impl<I, J> ExactSizeIterator for ZipStretch<I, J>  | 
 | 99 | +where  | 
 | 100 | +    I: ExactSizeIterator,  | 
 | 101 | +    J: ExactSizeIterator,  | 
 | 102 | +    <I as Iterator>::Item: Clone,  | 
 | 103 | +    <J as Iterator>::Item: Clone,  | 
 | 104 | +{  | 
 | 105 | +}  | 
0 commit comments