|
| 1 | +use crate::char; |
1 | 2 | use crate::convert::TryFrom;
|
2 | 3 | use crate::mem;
|
3 | 4 | use crate::ops::{self, Add, Sub, Try};
|
@@ -400,6 +401,73 @@ step_integer_impls! {
|
400 | 401 | wider than usize: [u32 i32], [u64 i64], [u128 i128];
|
401 | 402 | }
|
402 | 403 |
|
| 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; |
| 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 | + // SAFETY: res is a valid unicode scalar |
| 431 | + // (below 0x110000 and not in 0xD800..0xE000) |
| 432 | + Some(unsafe { char::from_u32_unchecked(res) }) |
| 433 | + } else { |
| 434 | + None |
| 435 | + } |
| 436 | + } |
| 437 | + |
| 438 | + #[inline] |
| 439 | + fn backward_checked(start: char, count: usize) -> Option<char> { |
| 440 | + let start = start as u32; |
| 441 | + let mut res = Step::backward_checked(start, count)?; |
| 442 | + if start >= 0xE000 && 0xE000 > res { |
| 443 | + res = Step::backward_checked(res, 0x800)?; |
| 444 | + } |
| 445 | + // SAFETY: res is a valid unicode scalar |
| 446 | + // (below 0x110000 and not in 0xD800..0xE000) |
| 447 | + Some(unsafe { char::from_u32_unchecked(res) }) |
| 448 | + } |
| 449 | + |
| 450 | + #[inline] |
| 451 | + unsafe fn forward_unchecked(start: char, count: usize) -> char { |
| 452 | + let start = start as u32; |
| 453 | + let mut res = Step::forward_unchecked(start, count); |
| 454 | + if start < 0xD800 && 0xD800 <= res { |
| 455 | + res = Step::forward_unchecked(res, 0x800); |
| 456 | + } |
| 457 | + char::from_u32_unchecked(res) |
| 458 | + } |
| 459 | + |
| 460 | + #[inline] |
| 461 | + unsafe fn backward_unchecked(start: char, count: usize) -> char { |
| 462 | + let start = start as u32; |
| 463 | + let mut res = Step::backward_unchecked(start, count); |
| 464 | + if start >= 0xE000 && 0xE000 > res { |
| 465 | + res = Step::backward_unchecked(res, 0x800); |
| 466 | + } |
| 467 | + char::from_u32_unchecked(res) |
| 468 | + } |
| 469 | +} |
| 470 | + |
403 | 471 | macro_rules! range_exact_iter_impl {
|
404 | 472 | ($($t:ty)*) => ($(
|
405 | 473 | #[stable(feature = "rust1", since = "1.0.0")]
|
@@ -582,7 +650,11 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
582 | 650 | }
|
583 | 651 | let is_iterating = self.start < self.end;
|
584 | 652 | Some(if is_iterating {
|
585 |
| - let n = Step::forward(self.start.clone(), 1); |
| 653 | + // SAFETY: just checked precondition |
| 654 | + // We use the unchecked version here, because |
| 655 | + // otherwise `for _ in '\0'..=char::MAX` |
| 656 | + // does not successfully remove panicking code. |
| 657 | + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; |
586 | 658 | mem::replace(&mut self.start, n)
|
587 | 659 | } else {
|
588 | 660 | self.exhausted = true;
|
|
0 commit comments