Rollup merge of #137432 - djscythe:char_u8_str_as_ascii_unchecked, r=scottmcm

Add as_ascii_unchecked() methods to char, u8, and str

This PR adds the `as_ascii_unchecked()` method to `char`, `u8`, and `str`, allowing users to convert these types to `ascii::Char`s (see #110998) in an `unsafe` context without first checking for validity. This method was already available for `[u8]`, so this PR makes the API more consistent across other types.
This commit is contained in:
Matthias Krüger 2025-05-17 15:45:19 +02:00 committed by GitHub
commit eb01ba0b57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 0 deletions

View file

@ -4,6 +4,7 @@ use super::*;
use crate::panic::const_panic;
use crate::slice;
use crate::str::from_utf8_unchecked_mut;
use crate::ub_checks::assert_unsafe_precondition;
use crate::unicode::printable::is_printable;
use crate::unicode::{self, conversions};
@ -1202,6 +1203,26 @@ impl char {
}
}
/// Converts this char into an [ASCII character](`ascii::Char`), without
/// checking whether it is valid.
///
/// # Safety
///
/// This char must be within the ASCII range, or else this is UB.
#[must_use]
#[unstable(feature = "ascii_char", issue = "110998")]
#[inline]
pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char {
assert_unsafe_precondition!(
check_library_ub,
"as_ascii_unchecked requires that the char is valid ASCII",
(it: &char = self) => it.is_ascii()
);
// SAFETY: the caller promised that this char is ASCII.
unsafe { ascii::Char::from_u8_unchecked(*self as u8) }
}
/// Makes a copy of the value in its ASCII upper case equivalent.
///
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',

View file

@ -492,6 +492,26 @@ impl u8 {
ascii::Char::from_u8(*self)
}
/// Converts this byte to an [ASCII character](ascii::Char), without
/// checking whether or not it's valid.
///
/// # Safety
///
/// This byte must be valid ASCII, or else this is UB.
#[must_use]
#[unstable(feature = "ascii_char", issue = "110998")]
#[inline]
pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char {
assert_unsafe_precondition!(
check_library_ub,
"as_ascii_unchecked requires that the byte is valid ASCII",
(it: &u8 = self) => it.is_ascii()
);
// SAFETY: the caller promised that this byte is ASCII.
unsafe { ascii::Char::from_u8_unchecked(*self) }
}
/// Makes a copy of the value in its ASCII upper case equivalent.
///
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',

View file

@ -17,6 +17,7 @@ use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher};
use crate::char::{self, EscapeDebugExtArgs};
use crate::ops::Range;
use crate::slice::{self, SliceIndex};
use crate::ub_checks::assert_unsafe_precondition;
use crate::{ascii, mem};
pub mod pattern;
@ -2634,6 +2635,27 @@ impl str {
self.as_bytes().as_ascii()
}
/// Converts this string slice into a slice of [ASCII characters](ascii::Char),
/// without checking whether they are valid.
///
/// # Safety
///
/// Every character in this string must be ASCII, or else this is UB.
#[unstable(feature = "ascii_char", issue = "110998")]
#[must_use]
#[inline]
pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] {
assert_unsafe_precondition!(
check_library_ub,
"as_ascii_unchecked requires that the string is valid ASCII",
(it: &str = self) => it.is_ascii()
);
// SAFETY: the caller promised that every byte of this string slice
// is ASCII.
unsafe { self.as_bytes().as_ascii_unchecked() }
}
/// Checks that two strings are an ASCII case-insensitive match.
///
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,