use core::{char, cmp};
#[cfg(feature = "std")]
use std::collections::Bound;
use self::cmp::Ordering;
use CharIter;
#[derive(Copy, Clone, Debug, Eq)]
pub struct CharRange {
pub low: char,
pub high: char,
}
impl CharRange {
pub fn closed(start: char, stop: char) -> CharRange {
CharRange {
low: start,
high: stop,
}
}
pub fn open_right(start: char, stop: char) -> CharRange {
let mut iter = CharRange::closed(start, stop).iter();
let _ = iter.next_back();
iter.into()
}
pub fn open_left(start: char, stop: char) -> CharRange {
let mut iter = CharRange::closed(start, stop).iter();
let _ = iter.next();
iter.into()
}
pub fn open(start: char, stop: char) -> CharRange {
let mut iter = CharRange::closed(start, stop).iter();
let _ = iter.next();
let _ = iter.next_back();
iter.into()
}
#[cfg(feature = "std")]
pub fn bound(start: Bound<char>, stop: Bound<char>) -> CharRange {
let start = if start == Bound::Unbounded {
Bound::Included('\0')
} else {
start
};
let stop = if stop == Bound::Unbounded {
Bound::Included(char::MAX)
} else {
stop
};
match (start, stop) {
(Bound::Included(start), Bound::Included(stop)) => CharRange::closed(start, stop),
(Bound::Excluded(start), Bound::Excluded(stop)) => CharRange::open(start, stop),
(Bound::Included(start), Bound::Excluded(stop)) => CharRange::open_right(start, stop),
(Bound::Excluded(start), Bound::Included(stop)) => CharRange::open_left(start, stop),
(Bound::Unbounded, _) | (_, Bound::Unbounded) => unreachable!(),
}
}
pub fn all() -> CharRange {
CharRange::closed('\0', char::MAX)
}
}
impl CharRange {
pub fn contains(&self, ch: char) -> bool {
self.low <= ch && ch <= self.high
}
#[cfg_attr(feature = "clippy", allow(should_implement_trait))]
pub fn cmp(&self, ch: char) -> Ordering {
assert!(!self.is_empty(), "Cannot compare empty range's ordering");
if self.high < ch {
Ordering::Less
} else if self.low > ch {
Ordering::Greater
} else {
Ordering::Equal
}
}
pub fn len(&self) -> usize {
self.iter().len()
}
pub fn is_empty(&self) -> bool {
self.low > self.high
}
pub fn iter(&self) -> CharIter {
(*self).into()
}
}
impl IntoIterator for CharRange {
type Item = char;
type IntoIter = CharIter;
fn into_iter(self) -> CharIter {
self.iter()
}
}
impl PartialEq<CharRange> for CharRange {
fn eq(&self, other: &CharRange) -> bool {
(self.is_empty() && other.is_empty()) || (self.low == other.low && self.high == other.high)
}
}