diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b4f08debc932a..232017f38bdd8 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -118,6 +118,7 @@ #![feature(fn_traits)] #![feature(formatting_options)] #![feature(hasher_prefixfree_extras)] +#![feature(inherent_str_constructors)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 6fee8d3fe3346..5ae82353461c7 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -12,6 +12,8 @@ use core::iter::FusedIterator; use core::mem::MaybeUninit; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::ParseBoolError; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] pub use core::str::SplitAsciiWhitespace; #[stable(feature = "split_inclusive", since = "1.51.0")] @@ -22,7 +24,7 @@ pub use core::str::SplitWhitespace; pub use core::str::pattern; use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher, Utf8Pattern}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut}; +pub use core::str::{Bytes, CharIndices, Chars}; #[stable(feature = "str_escape", since = "1.34.0")] pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; #[stable(feature = "rust1", since = "1.0.0")] @@ -35,8 +37,6 @@ pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{ParseBoolError, from_utf8_unchecked, from_utf8_unchecked_mut}; -#[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplit, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; @@ -46,6 +46,8 @@ pub use core::str::{RSplitTerminator, SplitTerminator}; pub use core::str::{Utf8Chunk, Utf8Chunks}; #[unstable(feature = "str_from_raw_parts", issue = "119206")] pub use core::str::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{from_utf8, from_utf8_mut, from_utf8_unchecked, from_utf8_unchecked_mut}; use core::unicode::conversions; use core::{mem, ptr}; @@ -698,7 +700,7 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { // SAFETY: we know this is a valid char boundary // since we only skipped over leading ascii bytes - let rest = core::str::from_utf8_unchecked(slice); + let rest = str::from_utf8_unchecked(slice); (ascii_string, rest) } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 0c9535dfaa628..983d9b85e3936 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -62,7 +62,7 @@ use crate::alloc::Allocator; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, CharIndices, Chars, Utf8Error, from_utf8_unchecked_mut}; +use crate::str::{CharIndices, Chars, Utf8Error}; #[cfg(not(no_global_oom_handling))] use crate::str::{FromStr, from_boxed_utf8_unchecked}; use crate::vec::{self, Vec}; @@ -2110,7 +2110,7 @@ impl String { #[inline] pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); - unsafe { from_utf8_unchecked_mut(slice) } + unsafe { str::from_utf8_unchecked_mut(slice) } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8eee7cff2080d..a722d4c27dafa 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3508,7 +3508,7 @@ impl Default for Arc { #[inline] fn default() -> Self { let arc: Arc<[u8]> = Default::default(); - debug_assert!(core::str::from_utf8(&*arc).is_ok()); + debug_assert!(str::from_utf8(&*arc).is_ok()); let (ptr, alloc) = Arc::into_inner_with_allocator(arc); unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner, alloc) } } diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index fb8a740aced13..49427daf6b057 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -3,7 +3,6 @@ use super::*; use crate::panic::const_panic; use crate::slice; -use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; use crate::unicode::{self, conversions}; @@ -701,7 +700,7 @@ impl char { #[inline] pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str { // 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 { str::from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } /// Encodes this character as UTF-16 into the provided `u16` buffer, diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 7180593edf0d0..0ecd515299036 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -8,7 +8,7 @@ use crate::iter::FusedIterator; use crate::marker::PhantomData; use crate::ptr::NonNull; use crate::slice::memchr; -use crate::{fmt, ops, slice, str}; +use crate::{fmt, ops, slice}; // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link // depends on where the item is being documented. however, since this is libcore, we can't @@ -651,7 +651,7 @@ impl CStr { /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] - pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { + pub const fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a033b8bd30514..ba241efafab05 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::EscapeDebugExtArgs; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, mem, result}; mod builders; #[cfg(not(no_fp_fmt_parse))] diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 683e45b35f70a..e215624af135c 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -3,7 +3,7 @@ use crate::mem::MaybeUninit; use crate::num::fmt as numfmt; use crate::ops::{Div, Rem, Sub}; -use crate::{fmt, ptr, slice, str}; +use crate::{fmt, ptr, slice}; #[doc(hidden)] trait DisplayInt: diff --git a/library/core/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs index 625ad5401f5c0..a113057c27af4 100644 --- a/library/core/src/net/display_buffer.rs +++ b/library/core/src/net/display_buffer.rs @@ -1,5 +1,5 @@ +use crate::fmt; use crate::mem::MaybeUninit; -use crate::{fmt, str}; /// Used for slow path in `Display` implementations when alignment is required. pub(super) struct DisplayBuffer { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 51b25fa40e3d9..1667d38b2d409 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -302,7 +302,7 @@ impl<'a> fmt::Display for EscapeAscii<'a> { // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) }; // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII - let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) }; + let prefix = unsafe { str::from_utf8_unchecked(prefix) }; f.write_str(prefix)?; // the fast part diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index de68f80aa0c8e..730cafa8a0543 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,8 +1,7 @@ //! Ways to create a `str` from bytes slice. use super::Utf8Error; -use super::validations::run_utf8_validation; -use crate::{mem, ptr}; +use crate::ptr; /// Converts a slice of bytes to a string slice. /// @@ -85,14 +84,7 @@ use crate::{mem, ptr}; #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - // FIXME(const-hack): This should use `?` again, once it's `const` - match run_utf8_validation(v) { - Ok(_) => { - // SAFETY: validation succeeded. - Ok(unsafe { from_utf8_unchecked(v) }) - } - Err(err) => Err(err), - } + str::from_utf8(v) } /// Converts a mutable slice of bytes to a mutable string slice. @@ -129,14 +121,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - // FIXME(const-hack): This should use `?` again, once it's `const` - match run_utf8_validation(v) { - Ok(_) => { - // SAFETY: validation succeeded. - Ok(unsafe { from_utf8_unchecked_mut(v) }) - } - Err(err) => Err(err), - } + str::from_utf8_mut(v) } /// Converts a slice of bytes to a string slice without checking @@ -168,11 +153,10 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] -#[rustc_diagnostic_item = "str_from_utf8_unchecked"] +#[rustc_diagnostic_item = "from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { - // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. - // Also relies on `&str` and `&[u8]` having the same layout. - unsafe { mem::transmute(v) } + // SAFETY: same requirements + unsafe { str::from_utf8_unchecked(v) } } /// Converts a slice of bytes to a string slice without checking @@ -196,13 +180,10 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked_mut", since = "1.83.0")] -#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] +#[rustc_diagnostic_item = "from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { - // SAFETY: the caller must guarantee that the bytes `v` - // are valid UTF-8, thus the cast to `*mut str` is safe. - // Also, the pointer dereference is safe because that pointer - // comes from a reference which is guaranteed to be valid for writes. - unsafe { &mut *(v as *mut [u8] as *mut str) } + // SAFETY: same requirements + unsafe { str::from_utf8_unchecked_mut(v) } } /// Creates a `&str` from a pointer and a length. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..a115c77b738f5 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -4,7 +4,7 @@ use super::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use super::validations::{next_code_point, next_code_point_reverse}; use super::{ BytesIsNotEmpty, CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode, - IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, from_utf8_unchecked, + IsAsciiWhitespace, IsNotEmpty, IsWhitespace, LinesMap, UnsafeBytesToStr, }; use crate::fmt::{self, Write}; use crate::iter::{ @@ -158,7 +158,7 @@ impl<'a> Chars<'a> { #[inline] pub fn as_str(&self) -> &'a str { // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. - unsafe { from_utf8_unchecked(self.iter.as_slice()) } + unsafe { str::from_utf8_unchecked(self.iter.as_slice()) } } } @@ -1413,7 +1413,7 @@ impl<'a> SplitAsciiWhitespace<'a> { } // SAFETY: Slice is created from str. - Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }) + Some(unsafe { str::from_utf8_unchecked(&self.inner.iter.iter.v) }) } } diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index ed2cefc59a51c..816a3aba3680c 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,4 +1,3 @@ -use super::from_utf8_unchecked; use super::validations::utf8_char_width; use crate::fmt; use crate::fmt::{Formatter, Write}; @@ -281,7 +280,7 @@ impl<'a> Iterator for Utf8Chunks<'a> { Some(Utf8Chunk { // SAFETY: All bytes up to `valid_up_to` are valid UTF-8. - valid: unsafe { from_utf8_unchecked(valid) }, + valid: unsafe { str::from_utf8_unchecked(valid) }, invalid, }) } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 8a473b398bb5f..4263f4223bceb 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,6 +13,8 @@ mod iter; mod traits; mod validations; +use validations::run_utf8_validation; + use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::ops::Range; @@ -160,6 +162,193 @@ impl str { self.len() == 0 } + /// Converts a slice of bytes to a string slice. + /// + /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice + /// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between + /// the two. Not all byte slices are valid string slices, however: [`&str`] requires + /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid + /// UTF-8, and then does the conversion. + /// + /// [`&str`]: str + /// [byteslice]: slice + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want to + /// incur the overhead of the validity check, there is an unsafe version of + /// this function, [`from_utf8_unchecked`], which has the same + /// behavior but skips the check. + /// + /// If you need a `String` instead of a `&str`, consider + /// [`String::from_utf8`][string]. + /// + /// [string]: ../../std/string/struct.String.html#method.from_utf8 + /// + /// Because you can stack-allocate a `[u8; N]`, and you can take a + /// [`&[u8]`][byteslice] of it, this function is one way to have a + /// stack-allocated string. There is an example of this in the + /// examples section below. + /// + /// [byteslice]: slice + /// + /// # Errors + /// + /// Returns `Err` if the slice is not UTF-8 with a description as to why the + /// provided slice is not UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// assert!(str::from_utf8(&sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + /// + /// A "stack allocated string": + /// + /// ``` + /// // some bytes, in a stack-allocated array + /// let sparkle_heart = [240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart: &str = str::from_utf8(&sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_allow_const_fn_unstable(str_internals)] + pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + // FIXME(const-hack): This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { Self::from_utf8_unchecked(v) }) + } + Err(err) => Err(err), + } + } + + /// Converts a mutable slice of bytes to a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // "Hello, Rust!" as a mutable vector + /// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; + /// + /// // As we know these bytes are valid, we can use `unwrap()` + /// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); + /// + /// assert_eq!("Hello, Rust!", outstr); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use std::str; + /// + /// // Some invalid bytes in a mutable vector + /// let mut invalid = vec![128, 223]; + /// + /// assert!(str::from_utf8_mut(&mut invalid).is_err()); + /// ``` + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + // FIXME(const-hack): This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { Self::from_utf8_unchecked_mut(v) }) + } + Err(err) => Err(err), + } + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8. + /// + /// See the safe version, [`from_utf8`], for more information. + /// + /// # Safety + /// + /// The bytes passed in must be valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// let sparkle_heart = unsafe { + /// str::from_utf8_unchecked(&sparkle_heart) + /// }; + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { + // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. + // Also relies on `&str` and `&[u8]` having the same layout. + unsafe { mem::transmute(v) } + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8; mutable version. + /// + /// See the immutable version, [`from_utf8_unchecked()`] for more information. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// let mut heart = vec![240, 159, 146, 150]; + /// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; + /// + /// assert_eq!("💖", heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + // SAFETY: the caller must guarantee that the bytes `v` + // are valid UTF-8, thus the cast to `*mut str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for writes. + unsafe { &mut *(v as *mut [u8] as *mut str) } + } + /// Checks that `index`-th byte is the first byte in a UTF-8 code point /// sequence or the end of the string. /// @@ -805,8 +994,8 @@ impl str { // SAFETY: caller guarantees `mid` is on a char boundary. unsafe { ( - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), - from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), + str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), + str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)), ) } } @@ -2561,7 +2750,7 @@ impl str { pub const fn trim_ascii_start(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_start()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii_start()) } } /// Returns a string slice with trailing ASCII whitespace removed. @@ -2586,7 +2775,7 @@ impl str { pub const fn trim_ascii_end(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_end()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii_end()) } } /// Returns a string slice with leading and trailing ASCII whitespace @@ -2612,7 +2801,7 @@ impl str { pub const fn trim_ascii(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate // UTF-8. - unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } + unsafe { str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } } /// Returns an iterator that escapes each char in `self` with [`char::escape_debug`]. @@ -2808,7 +2997,7 @@ impl Default for &mut str { #[inline] fn default() -> Self { // SAFETY: The empty string is valid UTF-8. - unsafe { from_utf8_unchecked_mut(&mut []) } + unsafe { str::from_utf8_unchecked_mut(&mut []) } } } @@ -2862,7 +3051,7 @@ impl_fn_for_zst! { #[derive(Clone)] struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str { // SAFETY: not safe - unsafe { from_utf8_unchecked(bytes) } + unsafe { str::from_utf8_unchecked(bytes) } }; } diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 22bd46c567eaa..172eb89d9439c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1327,7 +1327,7 @@ impl fmt::Debug for Duration { if end > 0 { // SAFETY: We are only writing ASCII digits into the buffer and // it was initialized with '0's, so it contains valid UTF8. - let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + let s = unsafe { str::from_utf8_unchecked(&buf[..end]) }; // If the user request a precision > 9, we pad '0's at the end. let w = f.precision().unwrap_or(pos); diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 28f16da1ed8d2..6dd3ce83c77cc 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -16,7 +16,7 @@ use crate::path::Path; use crate::sync::Arc; use crate::sys_common::io::test::{TempDir, tmpdir}; use crate::time::{Duration, Instant, SystemTime}; -use crate::{env, str, thread}; +use crate::{env, thread}; macro_rules! check { ($e:expr) => { diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 8b46738ab8aee..cf1d5d8c5927a 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -437,7 +437,7 @@ impl Read for BufReader { // buffer. let mut bytes = Vec::new(); self.read_to_end(&mut bytes)?; - let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; + let string = str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; *buf += string; Ok(string.len()) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 17f6107aa030c..03c9d326a6157 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1023,9 +1023,7 @@ struct WriteRecorder { impl Write for WriteRecorder { fn write(&mut self, buf: &[u8]) -> io::Result { - use crate::str::from_utf8; - - self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); + self.events.push(RecordedEvent::Write(str::from_utf8(buf).unwrap().to_string())); Ok(buf.len()) } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index b2ffeb0f95d0d..06343e0ad478b 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -389,8 +389,7 @@ where } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - let content = - crate::str::from_utf8(Cursor::split(self).1).map_err(|_| io::Error::INVALID_UTF8)?; + let content = str::from_utf8(Cursor::split(self).1).map_err(|_| io::Error::INVALID_UTF8)?; let len = content.len(); buf.try_reserve(len)?; buf.push_str(content); diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index b952c85addf65..70cada395b045 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -4,7 +4,7 @@ mod tests; use crate::alloc::Allocator; use crate::collections::VecDeque; use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; -use crate::{cmp, fmt, mem, str}; +use crate::{cmp, fmt, mem}; // ============================================================================= // Forwarding implementations diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 231c8712ebd55..9f5eec9714ac6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -331,7 +331,7 @@ pub use self::{ use crate::mem::take; use crate::ops::{Deref, DerefMut}; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; -use crate::{cmp, fmt, slice, str, sys}; +use crate::{cmp, fmt, slice, sys}; mod buffered; pub(crate) mod copy; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 39f234e4ba661..53f5d11fbad2a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -337,6 +337,7 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_must_use)] +#![feature(inherent_str_constructors)] #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_slice)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e0dd2e14817a8..a920845eb7bfa 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -170,7 +170,7 @@ use crate::sys::process as imp; #[stable(feature = "command_access", since = "1.57.0")] pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -use crate::{fmt, fs, str}; +use crate::{fmt, fs}; /// Representation of a running or exited child process. /// diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index e8cbfe337bccf..19eaa2c1bd790 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -2,7 +2,6 @@ use super::{Command, Output, Stdio}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind}; use crate::mem::MaybeUninit; -use crate::str; fn known_command() -> Command { if cfg!(windows) { Command::new("help") } else { Command::new("echo") } diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8f..4da9433112a76 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -190,7 +190,7 @@ pub fn output_filename( } #[cfg(not(unix))] BytesOrWideString::Bytes(bytes) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() + Path::new(str::from_utf8(bytes).unwrap_or("")).into() } #[cfg(windows)] BytesOrWideString::Wide(wide) => { diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 5b65d862be102..290be0a519173 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -9,7 +9,7 @@ use crate::fmt::Write; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::{AsInner, IntoInner}; -use crate::{fmt, mem, str}; +use crate::{fmt, mem}; #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/uefi/stdio.rs b/library/std/src/sys/pal/uefi/stdio.rs index 703e8ba8e5710..7a3d6e59939a4 100644 --- a/library/std/src/sys/pal/uefi/stdio.rs +++ b/library/std/src/sys/pal/uefi/stdio.rs @@ -155,9 +155,9 @@ fn write( buf: &[u8], ) -> io::Result { // Get valid UTF-8 buffer - let utf8 = match crate::str::from_utf8(buf) { + let utf8 = match str::from_utf8(buf) { Ok(x) => x, - Err(e) => unsafe { crate::str::from_utf8_unchecked(&buf[..e.valid_up_to()]) }, + Err(e) => unsafe { str::from_utf8_unchecked(&buf[..e.valid_up_to()]) }, }; let mut utf16: Vec = utf8.encode_utf16().collect(); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index f657f82e6e368..2f74273fbe1c6 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -530,7 +530,6 @@ mod cgroups { use crate::io::{BufRead, Read}; use crate::os::unix::ffi::OsStringExt; use crate::path::{Path, PathBuf}; - use crate::str::from_utf8; #[derive(PartialEq)] enum Cgroup { @@ -559,7 +558,7 @@ mod cgroups { let version = match fields.nth(1) { Some(b"") => Cgroup::V2, Some(controllers) - if from_utf8(controllers) + if str::from_utf8(controllers) .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) => { Cgroup::V1 diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 7779d2b97d7f9..7a8ae12eaa229 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -844,7 +844,7 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { // necessary for entry in ReadDir::new(fd, dummy_root) { let entry = entry?; - let path = crate::str::from_utf8(&entry.name).map_err(|_| { + let path = str::from_utf8(&entry.name).map_err(|_| { io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index fd3f559ba1901..20ed81de6ecc1 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -7,7 +7,7 @@ use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::sys::handle::Handle; use crate::sys::{c, cvt}; -use crate::{cmp, io, ptr, str}; +use crate::{cmp, io, ptr}; #[cfg(test)] mod tests; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 6c60d901ee904..046934ca1cc56 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -29,7 +29,7 @@ use crate::iter::FusedIterator; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::AsInner; -use crate::{fmt, mem, ops, slice, str}; +use crate::{fmt, mem, ops, slice}; const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; @@ -656,7 +656,7 @@ impl Wtf8 { /// /// This does not copy the data. #[inline] - pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + pub fn as_str(&self) -> Result<&str, core::str::Utf8Error> { str::from_utf8(&self.bytes) } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 59b395336f2e3..b2dcdde17f165 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -171,7 +171,7 @@ use crate::sys::sync::Parker; use crate::sys::thread as imp; use crate::sys_common::{AsInner, IntoInner}; use crate::time::{Duration, Instant}; -use crate::{env, fmt, io, panic, panicking, str}; +use crate::{env, fmt, io, panic, panicking}; #[stable(feature = "scoped_threads", since = "1.63.0")] mod scoped; @@ -1257,7 +1257,6 @@ impl ThreadId { // This module ensures private fields are kept private, which is necessary to enforce the safety requirements. mod thread_name_string { use crate::ffi::{CStr, CString}; - use crate::str; /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated. pub(crate) struct ThreadNameString {