summaryrefslogtreecommitdiffstats
path: root/vendor/unic-char-range/src/range.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/unic-char-range/src/range.rs')
-rw-r--r--vendor/unic-char-range/src/range.rs231
1 files changed, 231 insertions, 0 deletions
diff --git a/vendor/unic-char-range/src/range.rs b/vendor/unic-char-range/src/range.rs
new file mode 100644
index 000000000..d958016fc
--- /dev/null
+++ b/vendor/unic-char-range/src/range.rs
@@ -0,0 +1,231 @@
+// 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, cmp};
+
+#[cfg(feature = "std")]
+use std::collections::Bound;
+
+use self::cmp::Ordering;
+use crate::CharIter;
+
+/// A range of unicode code points.
+///
+/// The most idiomatic way to construct this range is through the use of the `chars!` macro:
+///
+/// ```
+/// #[macro_use] extern crate unic_char_range;
+/// use unic_char_range::CharRange;
+///
+/// # fn main() {
+/// assert_eq!(chars!('a'..='z'), CharRange::closed('a', 'z'));
+/// assert_eq!(chars!('a'..'z'), CharRange::open_right('a', 'z'));
+/// assert_eq!(chars!(..), CharRange::all());
+/// # }
+/// ```
+///
+/// If constructed in reverse order, such that `self.high` is ordered before `self.low`,
+/// the range is empty. If you want to iterate in decreasing order, use `.iter().rev()`.
+/// All empty ranges are considered equal no matter the internal state.
+#[derive(Copy, Clone, Debug, Eq)]
+pub struct CharRange {
+ /// The lowest character in this range (inclusive).
+ pub low: char,
+
+ /// The highest character in this range (inclusive).
+ pub high: char,
+}
+
+/// Constructors
+impl CharRange {
+ /// Construct a closed range of characters.
+ ///
+ /// If `stop` is ordered before `start`, the resulting range will be empty.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use unic_char_range::*;
+ /// assert_eq!(
+ /// CharRange::closed('a', 'd').iter().collect::<Vec<_>>(),
+ /// vec!['a', 'b', 'c', 'd']
+ /// )
+ /// ```
+ pub fn closed(start: char, stop: char) -> CharRange {
+ CharRange {
+ low: start,
+ high: stop,
+ }
+ }
+
+ /// Construct a half open (right) range of characters.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use unic_char_range::*;
+ /// assert_eq!(
+ /// CharRange::open_right('a', 'd').iter().collect::<Vec<_>>(),
+ /// vec!['a', 'b', 'c']
+ /// )
+ /// ```
+ pub fn open_right(start: char, stop: char) -> CharRange {
+ let mut iter = CharRange::closed(start, stop).iter();
+ let _ = iter.next_back();
+ iter.into()
+ }
+
+ /// Construct a half open (left) range of characters.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use unic_char_range::*;
+ /// assert_eq!(
+ /// CharRange::open_left('a', 'd').iter().collect::<Vec<_>>(),
+ /// vec!['b', 'c', 'd']
+ /// )
+ /// ```
+ pub fn open_left(start: char, stop: char) -> CharRange {
+ let mut iter = CharRange::closed(start, stop).iter();
+ let _ = iter.next();
+ iter.into()
+ }
+
+ /// Construct a fully open range of characters.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use unic_char_range::*;
+ /// assert_eq!(
+ /// CharRange::open('a', 'd').iter().collect::<Vec<_>>(),
+ /// vec!['b', 'c']
+ /// )
+ /// ```
+ 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")]
+ /// Construct a range of characters from bounds.
+ pub fn bound(start: Bound<char>, stop: Bound<char>) -> CharRange {
+ let start = if start == Bound::Unbounded {
+ Bound::Included('\u{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!(),
+ }
+ }
+
+ /// Construct a range over all Unicode characters (Unicode Scalar Values).
+ pub fn all() -> CharRange {
+ CharRange::closed('\u{0}', char::MAX)
+ }
+
+ /// Construct a range over all characters of *assigned* Unicode Planes.
+ ///
+ /// Assigned *normal* (non-special) Unicode Planes are:
+ /// - Plane 0: *Basic Multilingual Plane* (BMP)
+ /// - Plane 1: *Supplementary Multilingual Plane* (SMP)
+ /// - Plane 2: *Supplementary Ideographic Plane* (SIP)
+ ///
+ /// Unicode Plane 14, *Supplementary Special-purpose Plane* (SSP), is not included in this
+ /// range, mainly because of the limit of `CharRange` only supporting a continuous range.
+ ///
+ /// Unicode Planes 3 to 13 are *Unassigned* planes and therefore excluded.
+ ///
+ /// Unicode Planes 15 and 16 are *Private Use Area* planes and won't have Unicode-assigned
+ /// characters.
+ pub fn assigned_normal_planes() -> CharRange {
+ CharRange::closed('\u{0}', '\u{2_FFFF}')
+ }
+}
+
+/// Collection-like fns
+impl CharRange {
+ /// Does this range include a character?
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use unic_char_range::CharRange;
+ /// assert!( CharRange::closed('a', 'g').contains('d'));
+ /// assert!( ! CharRange::closed('a', 'g').contains('z'));
+ ///
+ /// assert!( ! CharRange:: open ('a', 'a').contains('a'));
+ /// assert!( ! CharRange::closed('z', 'a').contains('g'));
+ /// ```
+ pub fn contains(&self, ch: char) -> bool {
+ self.low <= ch && ch <= self.high
+ }
+
+ /// Determine the ordering of this range and a character.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the range is empty. This fn may be adjusted in the future to not panic
+ /// in optimized builds. Even if so, an empty range will never compare as `Ordering::Equal`.
+ pub fn cmp_char(&self, ch: char) -> Ordering {
+ // possible optimization: only assert this in debug builds
+ 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
+ }
+ }
+
+ /// How many characters are in this range?
+ pub fn len(&self) -> usize {
+ self.iter().len()
+ }
+
+ /// Is this range empty?
+ pub fn is_empty(&self) -> bool {
+ self.low > self.high
+ }
+
+ /// Create an iterator over this range.
+ pub fn iter(&self) -> CharIter {
+ (*self).into()
+ }
+}
+
+impl IntoIterator for CharRange {
+ type IntoIter = CharIter;
+ type Item = char;
+
+ 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)
+ }
+}