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
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use crate::{Generator, GeneratorResult, ValueResult};
use core::num::NonZeroUsize;

/// A generator that generates values from a slice.
///
///
/// ## Example
/// ```
/// # use pushgen::{SliceGenerator, GeneratorExt};
/// let data = [1, 2, 3, 4];
/// let mut sum = 0;
/// SliceGenerator::new(&data).for_each(|x| sum += x);
/// assert_eq!(sum, 10);
/// ```
#[derive(Clone)]
pub struct SliceGenerator<'a, T> {
    slice: &'a [T],
    index: usize,
}

impl<'a, T> SliceGenerator<'a, T> {
    #[inline]
    pub fn new(slice: &'a [T]) -> Self {
        Self { slice, index: 0 }
    }
}

impl<'a, T> Generator for SliceGenerator<'a, T> {
    type Output = &'a T;

    #[inline]
    fn run(&mut self, mut output: impl FnMut(Self::Output) -> ValueResult) -> GeneratorResult {
        // Read the len once. The Rust compiler seems to have trouble optimizing self.slice.len()
        // so read it once and use that in the loop condition instead.
        let len = self.slice.len();
        while self.index < len {
            // Safety: self.index < self.slice.len() always true.
            if output(unsafe { self.slice.get_unchecked(self.index) }) == ValueResult::Stop {
                self.index += 1;
                return GeneratorResult::Stopped;
            }
            self.index += 1;
        }
        GeneratorResult::Complete
    }

    #[inline]
    fn try_advance(&mut self, n: NonZeroUsize) -> (usize, GeneratorResult) {
        let n = n.get();
        let len = self.slice.len();
        let available = len - self.index;
        if n >= available {
            self.index = len;
            (available, GeneratorResult::Complete)
        } else {
            self.index += n;
            (n, GeneratorResult::Stopped)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Generator, GeneratorExt};
    use core::num::NonZeroUsize;

    #[test]
    fn try_advance() {
        let data = [1, 2, 3, 4, 5];
        let mut gen = SliceGenerator::new(&data);
        let result = gen.try_advance(NonZeroUsize::new(3).unwrap());
        assert_eq!(result, (3, GeneratorResult::Stopped));
        assert_eq!(gen.next(), Ok(&4));
        assert_eq!(gen.next(), Ok(&5));
    }

    #[test]
    fn try_advance_inside() {
        let data = [1, 2, 3, 4, 5];
        let mut gen = SliceGenerator::new(&data);
        assert_eq!(gen.next(), Ok(&1));
        let result = gen.try_advance(NonZeroUsize::new(2).unwrap());
        assert_eq!(result, (2, GeneratorResult::Stopped));
        assert_eq!(gen.next(), Ok(&4));
        assert_eq!(gen.next(), Ok(&5));
    }

    #[test]
    fn try_advance_available() {
        let data = [1, 2, 3, 4, 5];
        let mut gen = SliceGenerator::new(&data);
        let result = gen.try_advance(NonZeroUsize::new(5).unwrap());
        assert_eq!(result, (5, GeneratorResult::Complete));
        assert_eq!(gen.next(), Err(GeneratorResult::Complete));
    }

    #[test]
    fn try_advance_more_than_available() {
        let data = [1, 2, 3, 4, 5];
        let mut gen = SliceGenerator::new(&data);
        let result = gen.try_advance(NonZeroUsize::new(10).unwrap());
        assert_eq!(result, (5, GeneratorResult::Complete));
        assert_eq!(gen.next(), Err(GeneratorResult::Complete));
    }
}