#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CharRange {
start: char,
end: char,
}
impl CharRange {
pub(crate) fn closed(start: char, end: char) -> Self {
Self { start, end }
}
pub(crate) fn contains(&self, c: char) -> bool {
c >= self.start && c <= self.end
}
pub(crate) fn all() -> CharRangeIter {
CharRangeIter {
current: '\0',
done: false,
}
}
}
pub(crate) struct CharRangeIter {
current: char,
done: bool,
}
impl Iterator for CharRangeIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let result = self.current;
let mut next_code_point = self.current as u32 + 1;
loop {
if next_code_point > 0x10FFFF {
self.done = true;
break;
}
match char::from_u32(next_code_point) {
Some(next_char) => {
self.current = next_char;
break;
}
None => {
next_code_point += 1;
}
}
}
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_char_range_contains() {
let range = CharRange::closed('a', 'z');
assert!(range.contains('a'));
assert!(range.contains('m'));
assert!(range.contains('z'));
assert!(!range.contains('A'));
assert!(!range.contains('0'));
}
#[test]
fn test_char_range_all() {
let all_chars: Vec<char> = CharRange::all().take(10).collect();
assert_eq!(all_chars[0], '\0');
assert_eq!(all_chars.len(), 10);
}
#[test]
fn test_char_range_all_count() {
let count = CharRange::all().count();
assert_eq!(count, 0x10F800);
}
}