cycle.rs - source
Description: Source of the Rust file `library/core/src/iter/adapters/cycle.rs`.
Keywords: rust, rustlang, rust-lang

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87

    use crate::{iter::FusedIterator, ops::Try};

    /// An iterator that repeats endlessly.
    ///
    /// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its
    /// documentation for more.
    ///
    /// [`cycle`]: Iterator::cycle
    /// [`Iterator`]: trait.Iterator.html
    #[derive(Clone, Debug)]
    #[must_use = "iterators are lazy and do nothing unless consumed"]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub struct Cycle<I> {
        orig: I,
        iter: I,
    }

    impl<I: Clone> Cycle<I> {
        pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
            Cycle { orig: iter.clone(), iter }
        }
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    impl<I> Iterator for Cycle<I>
    where
        I: Clone + Iterator,
    {
        type Item = <I as Iterator>::Item;

        #[inline]
        fn next(&mut self) -> Option<<I as Iterator>::Item> {
            match self.iter.next() {
                None => {
                    self.iter = self.orig.clone();
                    self.iter.next()
                }
                y => y,
            }
        }

        #[inline]
        fn size_hint(&self) -> (usize, Option<usize>) {
            // the cycle iterator is either empty or infinite
            match self.orig.size_hint() {
                sz @ (0, Some(0)) => sz,
                (0, _) => (0, None),
                _ => (usize::MAX, None),
            }
        }

        #[inline]
        fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
        where
            F: FnMut(Acc, Self::Item) -> R,
            R: Try<Ok = Acc>,
        {
            // fully iterate the current iterator. this is necessary because
            // `self.iter` may be empty even when `self.orig` isn't
            acc = self.iter.try_fold(acc, &mut f)?;
            self.iter = self.orig.clone();

            // complete a full cycle, keeping track of whether the cycled
            // iterator is empty or not. we need to return early in case
            // of an empty iterator to prevent an infinite loop
            let mut is_empty = true;
            acc = self.iter.try_fold(acc, |acc, x| {
                is_empty = false;
                f(acc, x)
            })?;

            if is_empty {
                return try { acc };
            }

            loop {
                self.iter = self.orig.clone();
                acc = self.iter.try_fold(acc, &mut f)?;
            }
        }

        // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
        // and we can't do anything better than the default.
    }

    #[stable(feature = "fused", since = "1.26.0")]
    impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}