Auto merge of #130511 - bjoernager:const-char-encode-utf8, r=dtolnay

Support `char::encode_utf8` in const scenarios.

This PR implements [`rust-lang/rfcs#3696`](https://github.com/rust-lang/rfcs/pull/3696/).

This assumes [`const_slice_from_raw_parts_mut`](https://github.com/rust-lang/rust/issues/67456/).
This commit is contained in:
bors
2024-09-19 04:17:04 +00:00
2 changed files with 15 additions and 18 deletions

View File

@@ -672,8 +672,9 @@ impl char {
/// 'ß'.encode_utf8(&mut b); /// 'ß'.encode_utf8(&mut b);
/// ``` /// ```
#[stable(feature = "unicode_encode_char", since = "1.15.0")] #[stable(feature = "unicode_encode_char", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")]
#[inline] #[inline]
pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
// SAFETY: `char` is not a surrogate, so this is valid UTF-8. // SAFETY: `char` is not a surrogate, so this is valid UTF-8.
unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) }
} }
@@ -1735,14 +1736,11 @@ impl EscapeDebugExtArgs {
#[inline] #[inline]
const fn len_utf8(code: u32) -> usize { const fn len_utf8(code: u32) -> usize {
if code < MAX_ONE_B { match code {
1 ..MAX_ONE_B => 1,
} else if code < MAX_TWO_B { ..MAX_TWO_B => 2,
2 ..MAX_THREE_B => 3,
} else if code < MAX_THREE_B { _ => 4,
3
} else {
4
} }
} }
@@ -1760,11 +1758,12 @@ const fn len_utf8(code: u32) -> usize {
/// Panics if the buffer is not large enough. /// Panics if the buffer is not large enough.
/// A buffer of length four is large enough to encode any `char`. /// A buffer of length four is large enough to encode any `char`.
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")]
#[doc(hidden)] #[doc(hidden)]
#[inline] #[inline]
pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
let len = len_utf8(code); let len = len_utf8(code);
match (len, &mut dst[..]) { match (len, &mut *dst) {
(1, [a, ..]) => { (1, [a, ..]) => {
*a = code as u8; *a = code as u8;
} }
@@ -1783,14 +1782,11 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
*c = (code >> 6 & 0x3F) as u8 | TAG_CONT; *c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
*d = (code & 0x3F) as u8 | TAG_CONT; *d = (code & 0x3F) as u8 | TAG_CONT;
} }
_ => panic!( // Note that we cannot format in constant expressions.
"encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", _ => panic!("encode_utf8: buffer does not have enough bytes to encode code point"),
len,
code,
dst.len(),
),
}; };
&mut dst[..len] // SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds.
unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) }
} }
/// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer, /// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer,

View File

@@ -119,6 +119,7 @@
#![feature(const_bigint_helper_methods)] #![feature(const_bigint_helper_methods)]
#![feature(const_black_box)] #![feature(const_black_box)]
#![feature(const_cell_into_inner)] #![feature(const_cell_into_inner)]
#![feature(const_char_encode_utf8)]
#![feature(const_eval_select)] #![feature(const_eval_select)]
#![feature(const_exact_div)] #![feature(const_exact_div)]
#![feature(const_float_classify)] #![feature(const_float_classify)]