use {
crate::{CharRange, AFTER_SURROGATE, BEFORE_SURROGATE},
core::{char, iter::FusedIterator},
};
#[derive(Clone, Debug)]
pub struct Iter {
low: char,
high: char,
}
impl IntoIterator for CharRange {
type Item = char;
type IntoIter = Iter;
#[allow(unsafe_code)]
fn into_iter(self) -> Iter {
Iter {
low: self.low,
high: self.high,
}
}
}
impl Iter {
#[inline]
fn step_forward(&mut self) {
if self.low == char::MAX {
self.high = '\0';
} else {
self.low = if self.low == BEFORE_SURROGATE {
AFTER_SURROGATE
} else {
#[allow(unsafe_code)]
unsafe {
char::from_u32_unchecked(self.low as u32 + 1)
}
}
}
}
#[inline]
fn step_backward(&mut self) {
if self.high == '\0' {
self.low = char::MAX;
} else {
self.high = if self.high == AFTER_SURROGATE {
BEFORE_SURROGATE
} else {
#[allow(unsafe_code)]
unsafe {
char::from_u32_unchecked(self.high as u32 - 1)
}
}
}
}
#[inline]
fn is_empty(&self) -> bool {
self.low > self.high
}
}
impl Iterator for Iter {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if (&*self).is_empty() {
return None;
}
let c = self.low;
self.step_forward();
Some(c)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
fn count(self) -> usize {
self.len()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl DoubleEndedIterator for Iter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if (&*self).is_empty() {
return None;
}
let c = self.high;
self.step_backward();
Some(c)
}
}
impl ExactSizeIterator for Iter {
fn len(&self) -> usize {
#[allow(clippy::range_plus_one)] let len = (self.low as u32..self.high as u32 + 1).len() as u32;
((if self.low <= BEFORE_SURROGATE && self.high >= AFTER_SURROGATE {
len - (AFTER_SURROGATE as u32 - (BEFORE_SURROGATE as u32 + 1))
} else {
len
}) as usize)
}
}
impl FusedIterator for Iter {}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
fn trivial(r: CharRange) -> impl Iterator<Item = char> + DoubleEndedIterator {
(r.low as u32..=r.high as u32).filter_map(char::from_u32)
}
#[test]
fn exact_size_iterator() {
let r = CharRange::from('a'..='z');
assert_eq!(
r.iter().enumerate().rev().collect::<Vec<_>>(),
trivial(r)
.enumerate()
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect::<Vec<_>>(),
);
}
#[test]
fn full_range() {
let r = CharRange::from(..);
assert_eq!(r.iter().count(), trivial(r).count());
assert_eq!(r.iter().collect::<Vec<_>>(), trivial(r).collect::<Vec<_>>());
}
#[test]
fn reverse_range() {
let r = CharRange::from(..);
assert_eq!(
r.iter().rev().collect::<Vec<_>>(),
trivial(r).rev().collect::<Vec<_>>(),
);
}
#[test]
fn surrogate_hug() {
let r = CharRange::from(BEFORE_SURROGATE..=AFTER_SURROGATE);
assert_eq!(r.iter().count(), trivial(r).count());
assert_eq!(r.iter().count(), trivial(r).count());
assert_eq!(r.iter().collect::<Vec<_>>(), r.iter().collect::<Vec<_>>());
}
#[test]
fn alphabet() {
let r = CharRange::from('a'..='z');
assert_eq!(r.iter().count(), trivial(r).count());
assert_eq!(r.iter().count(), trivial(r).count());
assert_eq!(r.iter().collect::<Vec<_>>(), trivial(r).collect::<Vec<_>>());
}
}