blob: 44901dfe3c0139b5cb9835acd6b6431b3d6e45e4 [file] [log] [blame]
// Copyright 2017 The UNIC Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::{char, ops};
use crate::{step, CharRange};
const SURROGATE_RANGE: ops::Range<u32> = 0xD800..0xE000;
/// An iterator over a range of unicode code points.
///
/// Constructed via `CharRange::iter`. See `CharRange` for more information.
#[derive(Clone, Debug)]
pub struct CharIter {
/// The lowest uniterated character (inclusive).
///
/// Iteration is finished if this is higher than `high`.
low: char,
/// The highest uniterated character (inclusive).
///
/// Iteration is finished if this is lower than `low`.
high: char,
}
impl From<CharRange> for CharIter {
fn from(range: CharRange) -> CharIter {
CharIter {
low: range.low,
high: range.high,
}
}
}
impl From<CharIter> for CharRange {
fn from(iter: CharIter) -> CharRange {
CharRange {
low: iter.low,
high: iter.high,
}
}
}
impl CharIter {
#[inline]
#[allow(unsafe_code)]
// When stepping `self.low` forward would go over `char::MAX`,
// Set `self.high` to `'\0'` instead. It will have the same effect --
// consuming the last element from the iterator and ending iteration.
fn step_forward(&mut self) {
if self.low == char::MAX {
self.high = '\0'
} else {
self.low = unsafe { step::forward(self.low) }
}
}
#[inline]
#[allow(unsafe_code)]
// When stepping `self.high` backward would cause underflow,
// set `self.low` to `char::MAX` instead. It will have the same effect --
// consuming the last element from the iterator and ending iteration.
fn step_backward(&mut self) {
if self.high == '\0' {
self.low = char::MAX;
} else {
self.high = unsafe { step::backward(self.high) }
}
}
#[inline]
/// ExactSizeIterator::is_empty() for stable
fn is_finished(&self) -> bool {
self.low > self.high
}
}
impl Iterator for CharIter {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
if self.is_finished() {
return None;
}
let ch = self.low;
self.step_forward();
Some(ch)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
fn last(self) -> Option<char> {
if self.is_finished() {
None
} else {
Some(self.high)
}
}
fn max(self) -> Option<char> {
self.last()
}
fn min(mut self) -> Option<char> {
self.next()
}
}
impl DoubleEndedIterator for CharIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.is_finished() {
None
} else {
let ch = self.high;
self.step_backward();
Some(ch)
}
}
}
impl ExactSizeIterator for CharIter {
fn len(&self) -> usize {
if self.is_finished() {
return 0;
}
let naive_range = (self.low as u32)..(self.high as u32 + 1);
if naive_range.start <= SURROGATE_RANGE.start && SURROGATE_RANGE.end <= naive_range.end {
naive_range.len() - SURROGATE_RANGE.len()
} else {
naive_range.len()
}
}
#[cfg(feature = "exact-size-is-empty")]
fn is_empty(&self) -> bool {
self.is_finished()
}
}