1use core::{char, ops};
12
13use crate::{step, CharRange};
14
15const SURROGATE_RANGE: ops::Range<u32> = 0xD800..0xE000;
16
17#[derive(Clone, Debug)]
21pub struct CharIter {
22    low: char,
26
27    high: char,
31}
32
33impl From<CharRange> for CharIter {
34    fn from(range: CharRange) -> CharIter {
35        CharIter {
36            low: range.low,
37            high: range.high,
38        }
39    }
40}
41
42impl From<CharIter> for CharRange {
43    fn from(iter: CharIter) -> CharRange {
44        CharRange {
45            low: iter.low,
46            high: iter.high,
47        }
48    }
49}
50
51impl CharIter {
52    #[inline]
53    #[allow(unsafe_code)]
54    fn step_forward(&mut self) {
58        if self.low == char::MAX {
59            self.high = '\0'
60        } else {
61            self.low = unsafe { step::forward(self.low) }
62        }
63    }
64
65    #[inline]
66    #[allow(unsafe_code)]
67    fn step_backward(&mut self) {
71        if self.high == '\0' {
72            self.low = char::MAX;
73        } else {
74            self.high = unsafe { step::backward(self.high) }
75        }
76    }
77
78    #[inline]
79    fn is_finished(&self) -> bool {
81        self.low > self.high
82    }
83}
84
85impl Iterator for CharIter {
86    type Item = char;
87
88    #[inline]
89    fn next(&mut self) -> Option<char> {
90        if self.is_finished() {
91            return None;
92        }
93
94        let ch = self.low;
95        self.step_forward();
96        Some(ch)
97    }
98
99    fn size_hint(&self) -> (usize, Option<usize>) {
100        let len = self.len();
101        (len, Some(len))
102    }
103
104    fn last(self) -> Option<char> {
105        if self.is_finished() {
106            None
107        } else {
108            Some(self.high)
109        }
110    }
111
112    fn max(self) -> Option<char> {
113        self.last()
114    }
115
116    fn min(mut self) -> Option<char> {
117        self.next()
118    }
119}
120
121impl DoubleEndedIterator for CharIter {
122    #[inline]
123    fn next_back(&mut self) -> Option<Self::Item> {
124        if self.is_finished() {
125            None
126        } else {
127            let ch = self.high;
128            self.step_backward();
129            Some(ch)
130        }
131    }
132}
133
134impl ExactSizeIterator for CharIter {
135    fn len(&self) -> usize {
136        if self.is_finished() {
137            return 0;
138        }
139        let naive_range = (self.low as u32)..(self.high as u32 + 1);
140        if naive_range.start <= SURROGATE_RANGE.start && SURROGATE_RANGE.end <= naive_range.end {
141            naive_range.len() - SURROGATE_RANGE.len()
142        } else {
143            naive_range.len()
144        }
145    }
146
147    #[cfg(feature = "exact-size-is-empty")]
148    fn is_empty(&self) -> bool {
149        self.is_finished()
150    }
151}