Skip to content

Commit 96f3879

Browse files
committed
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.
1 parent 3a7dfda commit 96f3879

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

src/libcore/iter/range.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::char;
12
use crate::convert::TryFrom;
23
use crate::mem;
34
use crate::ops::{self, Add, Sub, Try};
@@ -400,6 +401,69 @@ step_integer_impls! {
400401
wider than usize: [u32 i32], [u64 i64], [u128 i128];
401402
}
402403

404+
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
405+
unsafe impl Step for char {
406+
#[inline]
407+
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
408+
let start = start as u32;
409+
let end = end as u32;
410+
if start <= end {
411+
let count = end - start + 1;
412+
if start < 0xD800 && 0xE000 <= end {
413+
usize::try_from(count - 0x800).ok()
414+
} else {
415+
usize::try_from(count).ok()
416+
}
417+
} else {
418+
None
419+
}
420+
}
421+
422+
#[inline]
423+
fn forward_checked(start: char, count: usize) -> Option<char> {
424+
let start = start as u32;
425+
let mut res = Step::forward_checked(start, count)?;
426+
if start < 0xD800 && 0xD800 <= res {
427+
res = Step::forward_checked(res, 0x800)?;
428+
}
429+
if res <= char::MAX as u32 {
430+
Some(unsafe { char::from_u32_unchecked(res) })
431+
} else {
432+
None
433+
}
434+
}
435+
436+
#[inline]
437+
fn backward_checked(start: char, count: usize) -> Option<char> {
438+
let start = start as u32;
439+
let mut res = Step::backward_checked(start, count)?;
440+
if start >= 0xE000 && 0xE000 > res {
441+
res = Step::backward_checked(res, 0x800)?;
442+
}
443+
Some(unsafe { char::from_u32_unchecked(res) })
444+
}
445+
446+
#[inline]
447+
unsafe fn forward_unchecked(start: char, count: usize) -> char {
448+
let start = start as u32;
449+
let mut res = Step::forward_unchecked(start, count);
450+
if start < 0xD800 && 0xD800 <= res {
451+
res = Step::forward_unchecked(res, 0x800);
452+
}
453+
char::from_u32_unchecked(res)
454+
}
455+
456+
#[inline]
457+
unsafe fn backward_unchecked(start: char, count: usize) -> char {
458+
let start = start as u32;
459+
let mut res = Step::backward_unchecked(start, count);
460+
if start >= 0xE000 && 0xE000 > res {
461+
res = Step::backward_unchecked(res, 0x800);
462+
}
463+
char::from_u32_unchecked(res)
464+
}
465+
}
466+
403467
macro_rules! range_exact_iter_impl {
404468
($($t:ty)*) => ($(
405469
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)