Skip to content

Commit eb01ba0

Browse files
authored
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.
2 parents 836db3c + 101e24a commit eb01ba0

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

library/core/src/char/methods.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::*;
44
use crate::panic::const_panic;
55
use crate::slice;
66
use crate::str::from_utf8_unchecked_mut;
7+
use crate::ub_checks::assert_unsafe_precondition;
78
use crate::unicode::printable::is_printable;
89
use crate::unicode::{self, conversions};
910

@@ -1202,6 +1203,26 @@ impl char {
12021203
}
12031204
}
12041205

1206+
/// Converts this char into an [ASCII character](`ascii::Char`), without
1207+
/// checking whether it is valid.
1208+
///
1209+
/// # Safety
1210+
///
1211+
/// This char must be within the ASCII range, or else this is UB.
1212+
#[must_use]
1213+
#[unstable(feature = "ascii_char", issue = "110998")]
1214+
#[inline]
1215+
pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char {
1216+
assert_unsafe_precondition!(
1217+
check_library_ub,
1218+
"as_ascii_unchecked requires that the char is valid ASCII",
1219+
(it: &char = self) => it.is_ascii()
1220+
);
1221+
1222+
// SAFETY: the caller promised that this char is ASCII.
1223+
unsafe { ascii::Char::from_u8_unchecked(*self as u8) }
1224+
}
1225+
12051226
/// Makes a copy of the value in its ASCII upper case equivalent.
12061227
///
12071228
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',

library/core/src/num/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,26 @@ impl u8 {
492492
ascii::Char::from_u8(*self)
493493
}
494494

495+
/// Converts this byte to an [ASCII character](ascii::Char), without
496+
/// checking whether or not it's valid.
497+
///
498+
/// # Safety
499+
///
500+
/// This byte must be valid ASCII, or else this is UB.
501+
#[must_use]
502+
#[unstable(feature = "ascii_char", issue = "110998")]
503+
#[inline]
504+
pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char {
505+
assert_unsafe_precondition!(
506+
check_library_ub,
507+
"as_ascii_unchecked requires that the byte is valid ASCII",
508+
(it: &u8 = self) => it.is_ascii()
509+
);
510+
511+
// SAFETY: the caller promised that this byte is ASCII.
512+
unsafe { ascii::Char::from_u8_unchecked(*self) }
513+
}
514+
495515
/// Makes a copy of the value in its ASCII upper case equivalent.
496516
///
497517
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',

library/core/src/str/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher};
1717
use crate::char::{self, EscapeDebugExtArgs};
1818
use crate::ops::Range;
1919
use crate::slice::{self, SliceIndex};
20+
use crate::ub_checks::assert_unsafe_precondition;
2021
use crate::{ascii, mem};
2122

2223
pub mod pattern;
@@ -2634,6 +2635,27 @@ impl str {
26342635
self.as_bytes().as_ascii()
26352636
}
26362637

2638+
/// Converts this string slice into a slice of [ASCII characters](ascii::Char),
2639+
/// without checking whether they are valid.
2640+
///
2641+
/// # Safety
2642+
///
2643+
/// Every character in this string must be ASCII, or else this is UB.
2644+
#[unstable(feature = "ascii_char", issue = "110998")]
2645+
#[must_use]
2646+
#[inline]
2647+
pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] {
2648+
assert_unsafe_precondition!(
2649+
check_library_ub,
2650+
"as_ascii_unchecked requires that the string is valid ASCII",
2651+
(it: &str = self) => it.is_ascii()
2652+
);
2653+
2654+
// SAFETY: the caller promised that every byte of this string slice
2655+
// is ASCII.
2656+
unsafe { self.as_bytes().as_ascii_unchecked() }
2657+
}
2658+
26372659
/// Checks that two strings are an ASCII case-insensitive match.
26382660
///
26392661
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,

0 commit comments

Comments
 (0)