From 7272b6fc8ce5c5d4b087129029c0a5be2570dd44 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 25 Sep 2021 23:57:26 +0200 Subject: [PATCH] Make char conversion functions unstably const --- library/core/src/char/convert.rs | 32 ++++++++++++++++++++++---------- library/core/src/char/methods.rs | 15 ++++++++++----- library/core/src/lib.rs | 1 + 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 72921414fb3..6e48faba84c 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -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::try_from(i).ok() +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +pub const fn from_u32(i: u32) -> Option { + // 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 { #[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) } } } @@ -244,18 +250,23 @@ impl FromStr for char { } } +#[inline] +const fn char_try_from_u32(i: u32) -> Result { + 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 for char { type Error = CharTryFromError; #[inline] fn try_from(i: u32) -> Result { - 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) } } @@ -323,7 +334,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 { +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +pub const fn from_digit(num: u32, radix: u32) -> Option { if radix > 36 { panic!("from_digit: radix is too high (maximum 36)"); } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 3c4972bd3c9..d5ad0c385c7 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -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 { + pub const fn from_u32(i: u32) -> Option { 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 { + pub const fn from_digit(num: u32, radix: u32) -> Option { 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 { + pub const fn to_digit(self, radix: u32) -> Option { 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 diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7bc641c5276..43ba556af63 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -104,6 +104,7 @@ #![feature(const_bigint_helper_methods)] #![feature(const_caller_location)] #![feature(const_cell_into_inner)] +#![feature(const_char_convert)] #![feature(const_discriminant)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)]