about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCAD97 <cad97@cad97.com>2020-05-20 23:46:57 -0400
committerCAD97 <cad97@cad97.com>2020-05-21 00:54:46 -0400
commit96f387920c21a83fa620b1838066fd4c73c4b486 (patch)
treefca025c1dd18616daaa7dfe407ffc842f1c561d5
parent3a7dfda40a3e798bf086bd58cc7e5e09deb808b5 (diff)
downloadrust-96f387920c21a83fa620b1838066fd4c73c4b486.tar.gz
rust-96f387920c21a83fa620b1838066fd4c73c4b486.zip
impl Step for char
Enables Range<char> to be iterable

Note: https://rust.godbolt.org/z/fdveKo
An iteration over all char ('\0'..=char::MAX)
includes unreachable panic code currently.
Updating RangeInclusive::next to call
Step::forward_unchecked (which is safe to do
but not done yet becuase it wasn't necessary)
successfully removes the panic from this iteration.
-rw-r--r--src/libcore/iter/range.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index d74df82bddd..6837aab7af1 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -1,3 +1,4 @@
+use crate::char;
 use crate::convert::TryFrom;
 use crate::mem;
 use crate::ops::{self, Add, Sub, Try};
@@ -400,6 +401,69 @@ step_integer_impls! {
     wider than usize: [u32 i32], [u64 i64], [u128 i128];
 }
 
+#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+unsafe impl Step for char {
+    #[inline]
+    fn steps_between(&start: &char, &end: &char) -> Option<usize> {
+        let start = start as u32;
+        let end = end as u32;
+        if start <= end {
+            let count = end - start + 1;
+            if start < 0xD800 && 0xE000 <= end {
+                usize::try_from(count - 0x800).ok()
+            } else {
+                usize::try_from(count).ok()
+            }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn forward_checked(start: char, count: usize) -> Option<char> {
+        let start = start as u32;
+        let mut res = Step::forward_checked(start, count)?;
+        if start < 0xD800 && 0xD800 <= res {
+            res = Step::forward_checked(res, 0x800)?;
+        }
+        if res <= char::MAX as u32 {
+            Some(unsafe { char::from_u32_unchecked(res) })
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn backward_checked(start: char, count: usize) -> Option<char> {
+        let start = start as u32;
+        let mut res = Step::backward_checked(start, count)?;
+        if start >= 0xE000 && 0xE000 > res {
+            res = Step::backward_checked(res, 0x800)?;
+        }
+        Some(unsafe { char::from_u32_unchecked(res) })
+    }
+
+    #[inline]
+    unsafe fn forward_unchecked(start: char, count: usize) -> char {
+        let start = start as u32;
+        let mut res = Step::forward_unchecked(start, count);
+        if start < 0xD800 && 0xD800 <= res {
+            res = Step::forward_unchecked(res, 0x800);
+        }
+        char::from_u32_unchecked(res)
+    }
+
+    #[inline]
+    unsafe fn backward_unchecked(start: char, count: usize) -> char {
+        let start = start as u32;
+        let mut res = Step::backward_unchecked(start, count);
+        if start >= 0xE000 && 0xE000 > res {
+            res = Step::backward_unchecked(res, 0x800);
+        }
+        char::from_u32_unchecked(res)
+    }
+}
+
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]