enumerate_split/
lib.rs

1
2/// Don't use this struct directly, use enumerate_split
3pub struct EnumerateSplit<Iter, T>
4where Iter: Iterator<Item = T>, T: PartialEq {
5    iter: Iter,
6    split_value: T,
7    block_number: usize,
8    block_position: usize
9}
10
11impl<Iter, T> EnumerateSplit<Iter, T>
12where Iter: Iterator<Item = T>, T: PartialEq {
13
14    #[inline]
15    fn nudge_block(&mut self) {
16        self.block_number += 1;
17        self.block_position = 0;
18    }
19
20    #[inline]
21    fn nudge_position(&mut self) {
22        self.block_position += 1;
23    }
24
25    #[inline]
26    fn get_position(&self) -> (usize, usize) {
27        (self.block_number, self.block_position)
28    }
29}
30
31/// Similar to enumerate but gives (usize, usize) where first
32/// is block number and second is block position (indexed by 0)
33///
34/// Can split on any possible T but useful to use `T=char`, `split_value='\n'`
35///
36///
37/// # Example
38/// ```
39/// use enumerate_split::enumerate_split;
40///
41/// let mut input = enumerate_split("Some \n\nstring with a newline".chars(), '\n');
42/// assert_eq!(input.next(), Some(('S', (0, 0))));
43/// assert_eq!(input.next(), Some(('o', (0, 1))));
44/// assert_eq!(input.next(), Some(('m', (0, 2))));
45/// assert_eq!(input.next(), Some(('e', (0, 3))));
46/// assert_eq!(input.next(), Some((' ', (0, 4))));
47/// assert_eq!(input.next(), Some(('\n', (0, 5))));
48/// assert_eq!(input.next(), Some(('\n', (1, 0))));
49/// assert_eq!(input.next(), Some(('s', (2, 0))));
50/// ```
51pub fn enumerate_split<Iter, T>(iter: Iter, split_value: T) -> EnumerateSplit<Iter, T>
52where Iter: Iterator<Item = T>, T: PartialEq {
53    EnumerateSplit {
54        iter: iter,
55        split_value: split_value,
56        block_number: 0,
57        block_position: 0
58    }
59}
60
61impl<Iter, T> Iterator for EnumerateSplit<Iter, T>
62where Iter: Iterator<Item = T>, T: PartialEq {
63    type Item = (T, (usize, usize));
64    fn next(&mut self) -> Option<(T, (usize, usize))> {
65        match self.iter.next() {
66            Some(t) => {
67                let split = t == self.split_value;
68                let res = Some((t, self.get_position()));
69                if split {
70                    self.nudge_block();
71                } else {
72                    self.nudge_position();
73                }
74                res
75            }
76            None => None
77        }
78    }
79}
80
81// Tests
82#[cfg(test)]
83mod tests {
84    use std::io::prelude::*;
85
86    #[test]
87    fn enumerate_split() {
88        let mut input = super::enumerate_split("Some \n\nstring with a newline".chars(), '\n');
89        assert_eq!(input.next(), Some(('S', (0, 0))));
90        assert_eq!(input.next(), Some(('o', (0, 1))));
91        assert_eq!(input.next(), Some(('m', (0, 2))));
92        assert_eq!(input.next(), Some(('e', (0, 3))));
93        assert_eq!(input.next(), Some((' ', (0, 4))));
94        assert_eq!(input.next(), Some(('\n', (0, 5))));
95        assert_eq!(input.next(), Some(('\n', (1, 0))));
96        assert_eq!(input.next(), Some(('s', (2, 0))));
97    }
98}
99