From ef3305449b7166153cce085d1cc5ffd30f470d0b Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 3 Jul 2023 13:11:39 -0400 Subject: [PATCH] Implement Step for AsciiChar --- library/core/src/iter/range.rs | 45 +++++++++++++++++++++++++++++++- library/core/tests/iter/range.rs | 18 ++++++++++++- library/core/tests/lib.rs | 2 ++ tests/ui/range/range-1.stderr | 2 +- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 462f7170a55b3..44feb0a5638e5 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,3 +1,4 @@ +use crate::ascii::Char as AsciiChar; use crate::convert::TryFrom; use crate::mem; use crate::num::NonZeroUsize; @@ -14,7 +15,7 @@ macro_rules! unsafe_impl_trusted_step { unsafe impl TrustedStep for $type {} )*}; } -unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -484,6 +485,48 @@ impl Step for char { } } +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for AsciiChar { + #[inline] + fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> Option { + Step::steps_between(&start.to_u8(), &end.to_u8()) + } + + #[inline] + fn forward_checked(start: AsciiChar, count: usize) -> Option { + let end = Step::forward_checked(start.to_u8(), count)?; + AsciiChar::from_u8(end) + } + + #[inline] + fn backward_checked(start: AsciiChar, count: usize) -> Option { + let end = Step::backward_checked(start.to_u8(), count)?; + + // SAFETY: Values below that of a valid ASCII character are also valid ASCII + Some(unsafe { AsciiChar::from_u8_unchecked(end) }) + } + + #[inline] + unsafe fn forward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::forward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } + + #[inline] + unsafe fn backward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::backward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 0a77ecddb84d5..5b87d6c1fa0e3 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -1,5 +1,6 @@ -use core::num::NonZeroUsize; use super::*; +use core::ascii::Char as AsciiChar; +use core::num::NonZeroUsize; #[test] fn test_range() { @@ -39,6 +40,21 @@ fn test_char_range() { assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); } +#[test] +fn test_ascii_char_range() { + let from = AsciiChar::Null; + let to = AsciiChar::Delete; + assert!((from..=to).eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8))); + assert!((from..=to).rev().eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8).rev())); + + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).count(), 26); + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).count(), 26); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).count(), 10); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).size_hint(), (10, Some(10))); +} + #[test] fn test_range_exhaustion() { let mut r = 10..10; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index d849561bb21b8..aac9250aa4fb8 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -2,6 +2,8 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] +#![feature(ascii_char)] +#![feature(ascii_char_variants)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 277d9b2682d8b..ecfc56961eed7 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -19,7 +19,7 @@ LL | for i in false..true {} i64 i128 usize - and 5 others + and 6 others = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator`