Rollup merge of #89258 - est31:const_char_convert, r=oli-obk
Make char conversion functions unstably const The char conversion functions like `char::from_u32` do trivial computations and can easily be converted into const fns. Only smaller tricks are needed to avoid non-const standard library functions like `Result::ok` or `bool::then_some`. Tracking issue: https://github.com/rust-lang/rust/issues/89259
This commit is contained in:
commit
7432588e5d
@ -51,8 +51,13 @@ use super::MAX;
|
||||
#[must_use]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn from_u32(i: u32) -> Option<char> {
|
||||
char::try_from(i).ok()
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
pub const fn from_u32(i: u32) -> Option<char> {
|
||||
// FIXME: once Result::ok is const fn, use it here
|
||||
match char_try_from_u32(i) {
|
||||
Ok(c) => Some(c),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `u32` to a `char`, ignoring validity.
|
||||
@ -91,7 +96,8 @@ pub fn from_u32(i: u32) -> Option<char> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
|
||||
pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
pub const unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
// SAFETY: the caller must guarantee that `i` is a valid char value.
|
||||
if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } }
|
||||
}
|
||||
@ -248,18 +254,23 @@ impl FromStr for char {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn char_try_from_u32(i: u32) -> Result<char, CharTryFromError> {
|
||||
if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
|
||||
Err(CharTryFromError(()))
|
||||
} else {
|
||||
// SAFETY: checked that it's a legal unicode value
|
||||
Ok(unsafe { transmute(i) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
impl TryFrom<u32> for char {
|
||||
type Error = CharTryFromError;
|
||||
|
||||
#[inline]
|
||||
fn try_from(i: u32) -> Result<Self, Self::Error> {
|
||||
if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
|
||||
Err(CharTryFromError(()))
|
||||
} else {
|
||||
// SAFETY: checked that it's a legal unicode value
|
||||
Ok(unsafe { transmute(i) })
|
||||
}
|
||||
char_try_from_u32(i)
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,7 +338,8 @@ impl fmt::Display for CharTryFromError {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
if radix > 36 {
|
||||
panic!("from_digit: radix is too high (maximum 36)");
|
||||
}
|
||||
|
@ -136,9 +136,10 @@ impl char {
|
||||
/// assert_eq!(None, c);
|
||||
/// ```
|
||||
#[stable(feature = "assoc_char_funcs", since = "1.52.0")]
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn from_u32(i: u32) -> Option<char> {
|
||||
pub const fn from_u32(i: u32) -> Option<char> {
|
||||
super::convert::from_u32(i)
|
||||
}
|
||||
|
||||
@ -178,9 +179,10 @@ impl char {
|
||||
/// assert_eq!('❤', c);
|
||||
/// ```
|
||||
#[stable(feature = "assoc_char_funcs", since = "1.52.0")]
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
pub const unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
// SAFETY: the safety contract must be upheld by the caller.
|
||||
unsafe { super::convert::from_u32_unchecked(i) }
|
||||
}
|
||||
@ -235,9 +237,10 @@ impl char {
|
||||
/// let _c = char::from_digit(1, 37);
|
||||
/// ```
|
||||
#[stable(feature = "assoc_char_funcs", since = "1.52.0")]
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
super::convert::from_digit(num, radix)
|
||||
}
|
||||
|
||||
@ -331,10 +334,11 @@ impl char {
|
||||
/// let _ = '1'.to_digit(37);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn to_digit(self, radix: u32) -> Option<u32> {
|
||||
pub const fn to_digit(self, radix: u32) -> Option<u32> {
|
||||
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
|
||||
// If not a digit, a number greater than radix will be created.
|
||||
let mut digit = (self as u32).wrapping_sub('0' as u32);
|
||||
@ -345,7 +349,8 @@ impl char {
|
||||
// Force the 6th bit to be set to ensure ascii is lower case.
|
||||
digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10);
|
||||
}
|
||||
(digit < radix).then_some(digit)
|
||||
// FIXME: once then_some is const fn, use it here
|
||||
if digit < radix { Some(digit) } else { None }
|
||||
}
|
||||
|
||||
/// Returns an iterator that yields the hexadecimal Unicode escape of a
|
||||
|
@ -105,6 +105,7 @@
|
||||
#![feature(const_bigint_helper_methods)]
|
||||
#![feature(const_caller_location)]
|
||||
#![feature(const_cell_into_inner)]
|
||||
#![feature(const_char_convert)]
|
||||
#![feature(const_discriminant)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_float_bits_conv)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user