1
use core::iter::Peekable;
2
use core::ops::Range;
3
use core::str::CharIndices;
4

            
5
#[derive(Debug, Clone)]
6
pub struct CharIterator<'a> {
7
    pub source: &'a str,
8
    chars: Peekable<CharIndices<'a>>,
9
    last: Option<(usize, char)>,
10
    marked_start: usize,
11
}
12

            
13
impl<'a> CharIterator<'a> {
14
    #[inline]
15
179
    pub fn new(source: &'a str) -> Self {
16
179
        Self {
17
179
            source,
18
179
            chars: source.char_indices().peekable(),
19
179
            last: None,
20
179
            marked_start: 0,
21
179
        }
22
179
    }
23

            
24
    #[inline]
25
386
    pub const fn last_offset(&self) -> usize {
26
386
        if let Some((offset, _)) = self.last {
27
386
            offset
28
        } else {
29
            0
30
        }
31
386
    }
32

            
33
    #[inline]
34
5264
    pub const fn current_offset(&self) -> usize {
35
5264
        if let Some((offset, ch)) = self.last {
36
5040
            offset + ch.len_utf8()
37
        } else {
38
224
            0
39
        }
40
5264
    }
41

            
42
    #[inline]
43
2042
    pub fn mark_start(&mut self) {
44
2042
        self.marked_start = self.current_offset();
45
2042
    }
46

            
47
    #[inline]
48
1512
    pub const fn marked_range(&self) -> Range<usize> {
49
1512
        self.marked_start..self.current_offset()
50
1512
    }
51

            
52
21
    pub fn marked_str(&self) -> &'a str {
53
21
        &self.source[self.marked_range()]
54
21
    }
55

            
56
    #[inline]
57
    pub const fn last_char_range(&self) -> Range<usize> {
58
        if let Some((offset, ch)) = self.last {
59
            offset..(offset + ch.len_utf8())
60
        } else {
61
            0..0
62
        }
63
    }
64

            
65
    #[inline]
66
7367
    pub fn next_char_and_index(&mut self) -> Option<(usize, char)> {
67
7367
        let current = self.chars.next()?;
68
7178
        self.last = Some(current);
69
7178
        Some(current)
70
7367
    }
71

            
72
    #[inline]
73
4820
    pub fn peek(&mut self) -> Option<char> {
74
4820
        self.peek_full().map(|(_, ch)| ch)
75
4820
    }
76

            
77
    #[inline]
78
4820
    pub fn peek_full(&mut self) -> Option<(usize, char)> {
79
4820
        self.chars.peek().copied()
80
4820
    }
81
}
82

            
83
impl<'a> Iterator for CharIterator<'a> {
84
    type Item = char;
85

            
86
    #[inline]
87
7367
    fn next(&mut self) -> Option<Self::Item> {
88
7367
        self.next_char_and_index().map(|(_, ch)| ch)
89
7367
    }
90
}