diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index 338c7ac7f8876..72ffb7db6887a 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -17,6 +17,7 @@ use core::{fmt, hash}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; +use crate::collections::TryReserveError; #[cfg(not(no_rc))] use crate::rc::Rc; use crate::string::String; @@ -44,32 +45,326 @@ use crate::vec::Vec; #[repr(transparent)] #[derive(Clone)] #[doc(alias = "BString")] -pub struct ByteString(pub Vec); +pub struct ByteString(pub(crate) Vec); impl ByteString { + /// Creates an empty `ByteString`. + #[unstable(feature = "bstr", issue = "134915")] #[inline] - pub(crate) fn as_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn new() -> ByteString { + ByteString(Vec::new()) + } + + /// Converts to a [`ByteStr`] slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let byte_str = ByteStr::new("foo"); + /// let byte_string = byte_str.to_byte_string(); + /// assert_eq!(byte_string.as_byte_str(), byte_str); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn as_byte_str(&self) -> &ByteStr { + ByteStr::new(&self.0) + } + + /// Converts to a mutable [`ByteStr`] slice. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn as_mut_byte_str(&mut self) -> &mut ByteStr { + ByteStr::new_mut(&mut self.0) + } + + /// Returns a reference to the underlying vector for this `ByteString`. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn as_vec(&self) -> &Vec { &self.0 } + /// Returns a mutable reference to the underlying vector for this `ByteString`. + #[unstable(feature = "bstr", issue = "134915")] #[inline] - pub(crate) fn as_bytestr(&self) -> &ByteStr { - ByteStr::new(&self.0) + pub fn as_mut_vec(&mut self) -> &mut Vec { + &mut self.0 + } + + /// Converts to a vector of bytes. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn into_bytes(self) -> Vec { + self.0 + } + + /// Converts to a boxed slice of bytes. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn into_boxed_bytes(self) -> Box<[u8]> { + self.into_bytes().into_boxed_slice() + } + + /// Converts to a boxed byte string. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn into_boxed_byte_str(self) -> Box { + self.into_bytes().into_boxed_slice().into_boxed_byte_str() + } + + /// Converts a `ByteString` into a [`String`] if it contains valid Unicode data. + /// + /// On failure, ownership of the original `ByteString` is returned. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn into_string(self) -> Result { + String::from_utf8(self.0).map_err(|e| ByteString(e.into_bytes())) + } + + /// Extends the byte string with the given &[ByteStr] slice. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn push>(&mut self, s: S) { + self.0.extend_from_slice(s.as_ref().as_bytes()) + } + + /// Pushes a single byte onto the byte string. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn push_byte(&mut self, b: u8) { + self.0.push(b) + } + + /// Creates a new [`ByteString`] with at least the given capacity. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn with_capacity(capacity: usize) -> ByteString { + ByteString(Vec::with_capacity(capacity)) } + /// Truncates the byte string to zero length. + #[unstable(feature = "bstr", issue = "134915")] #[inline] - pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0) + pub fn clear(&mut self) { + self.0.clear() + } + + /// Returns the number of bytes that can be pushed to this `ByteString` without reallocating. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn capacity(&self) -> usize { + self.0.capacity() + } + + /// Reserves capacity for at least `additional` more capacity to be inserted in the given + /// `ByteString`. Does nothing if the capacity is already sufficient. + /// + /// The collection may reserve more space to speculatively avoid frequent reallocations. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.0.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more bytes + /// in the given `ByteString`. The string may reserve more space to speculatively avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. This method preserves + /// the contents even if an error occurs. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.0.try_reserve(additional) + } + + /// Reserves the minimum capacity for at least `additional` more bytes to + /// be inserted in the given `ByteString`. Does nothing if the capacity is + /// already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: ByteString::reserve + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.0.reserve_exact(additional) + } + + /// Tries to reserve the minimum capacity for at least `additional` + /// more bytes in the given `ByteString`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `ByteString` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: ByteString::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.0.try_reserve_exact(additional) + } + + /// Shrinks the capacity of the `ByteString` to match its length. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn shrink_to_fit(&mut self) { + self.0.shrink_to_fit() + } + + /// Shrinks the capacity of the [`ByteString`] with a lower bound. + /// + /// The capacity will remain at least as large as both the length and the supplied value. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.0.shrink_to(min_capacity) + } + + /// Consumes and leaks the `ByteString`, returning a mutable reference to the contents, + /// `&'a mut ByteStr`. + /// + /// The caller has free choice over the returned lifetime, including `’static`. Indeed, this function is ideally used for data that lives for the remainder of the program’s life, as dropping the returned reference will cause a memory leak. + /// + /// It does not reallocate or shrink the `ByteString`, so the leaked allocation may include + /// unused capacity that is not part of the returned slice. If you want discard excess capacity, + /// call [`into_boxed_byte_str`], and then [`Box::leak`] instead. However, keep in mind that + /// trimming the capacity may result in a reallocation and copy. + /// + /// [`into_boxed_byte_str`]: ByteString::into_boxed_byte_str + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn leak<'a>(self) -> &'a mut ByteStr { + ByteStr::new_mut(self.0.leak()) + } + + /// Truncate the [`ByteString`] to the specified length. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn truncate(&mut self, len: usize) { + self.0.truncate(len) + } +} + +impl ByteStr { + /// Converts a `ByteStr` to a [Cow]<[str]>. + /// + /// Any non-UTF-8 sequences are replaced with + /// [U+FFFD REPLACEMENT CHARACTER][char::REPLACEMENT_CHARACTER]. + /// + /// # Examples + /// + /// Calling `to_string_lossy` on a `ByteStr` with invalid unicode: + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let bstr = ByteStr::new(b"hello, \x80\x80!"); + /// assert_eq!(bstr.to_string_lossy(), "hello, ��!"); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(self.as_bytes()) + } + + /// Converts a `ByteStr` to an owned [`ByteString`]. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn to_byte_string(&self) -> ByteString { + ByteString(self.as_bytes().to_vec()) + } + + /// Returns an owned [`ByteString`] containing a copy of this string where each byte + /// is mapped to its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// [`make_ascii_uppercase`]: ByteStr::make_ascii_uppercase + #[unstable(feature = "bstr", issue = "134915")] + #[must_use = "this returns the uppercase bytes as a new ByteString, \ + without modifying the original"] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn to_ascii_uppercase(&self) -> ByteString { + let mut me = self.to_byte_string(); + me.make_ascii_uppercase(); + me + } + + /// Returns an owned [`ByteString`] containing a copy of this string where each byte + /// is mapped to its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// [`make_ascii_lowercase`]: ByteStr::make_ascii_lowercase + #[unstable(feature = "bstr", issue = "134915")] + #[must_use = "this returns the uppercase bytes as a new ByteString, \ + without modifying the original"] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn to_ascii_lowercase(&self) -> ByteString { + let mut me = self.to_byte_string(); + me.make_ascii_lowercase(); + me + } + + /// Converts a [Box]<[ByteStr]> into a [Box]<\[u8\]> without + /// copying or allocating. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(self) as _) } + } + + /// Converts a [Box]<[ByteStr]> to an owned [`ByteString`]. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_allow_incoherent_impl] + pub fn into_byte_string(self: Box) -> ByteString { + ByteString(self.into_boxed_bytes().into_vec()) } } #[unstable(feature = "bstr", issue = "134915")] impl Deref for ByteString { - type Target = Vec; + type Target = ByteStr; #[inline] fn deref(&self) -> &Self::Target { - &self.0 + self.as_byte_str() } } @@ -77,7 +372,7 @@ impl Deref for ByteString { impl DerefMut for ByteString { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 + self.as_mut_byte_str() } } @@ -88,7 +383,7 @@ unsafe impl DerefPure for ByteString {} impl fmt::Debug for ByteString { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_bytestr(), f) + fmt::Debug::fmt(self.as_byte_str(), f) } } @@ -96,7 +391,7 @@ impl fmt::Debug for ByteString { impl fmt::Display for ByteString { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_bytestr(), f) + fmt::Display::fmt(self.as_byte_str(), f) } } @@ -104,7 +399,7 @@ impl fmt::Display for ByteString { impl AsRef<[u8]> for ByteString { #[inline] fn as_ref(&self) -> &[u8] { - &self.0 + self.as_bytes() } } @@ -112,7 +407,7 @@ impl AsRef<[u8]> for ByteString { impl AsRef for ByteString { #[inline] fn as_ref(&self) -> &ByteStr { - self.as_bytestr() + self.as_byte_str() } } @@ -120,7 +415,7 @@ impl AsRef for ByteString { impl AsMut<[u8]> for ByteString { #[inline] fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 + self.as_bytes_mut() } } @@ -128,7 +423,7 @@ impl AsMut<[u8]> for ByteString { impl AsMut for ByteString { #[inline] fn as_mut(&mut self) -> &mut ByteStr { - self.as_mut_bytestr() + self.as_mut_byte_str() } } @@ -136,7 +431,7 @@ impl AsMut for ByteString { impl Borrow<[u8]> for ByteString { #[inline] fn borrow(&self) -> &[u8] { - &self.0 + self.as_bytes() } } @@ -144,7 +439,7 @@ impl Borrow<[u8]> for ByteString { impl Borrow for ByteString { #[inline] fn borrow(&self) -> &ByteStr { - self.as_bytestr() + self.as_byte_str() } } @@ -155,7 +450,7 @@ impl Borrow for ByteString { impl BorrowMut<[u8]> for ByteString { #[inline] fn borrow_mut(&mut self) -> &mut [u8] { - &mut self.0 + self.as_bytes_mut() } } @@ -163,7 +458,7 @@ impl BorrowMut<[u8]> for ByteString { impl BorrowMut for ByteString { #[inline] fn borrow_mut(&mut self) -> &mut ByteStr { - self.as_mut_bytestr() + self.as_mut_byte_str() } } @@ -172,7 +467,7 @@ impl BorrowMut for ByteString { #[unstable(feature = "bstr", issue = "134915")] impl Default for ByteString { fn default() -> Self { - ByteString(Vec::new()) + ByteString::new() } } @@ -240,7 +535,7 @@ impl From for Vec { impl<'a> From<&'a ByteStr> for ByteString { #[inline] fn from(s: &'a ByteStr) -> Self { - ByteString(s.0.to_vec()) + s.to_byte_string() } } @@ -256,7 +551,7 @@ impl<'a> From for Cow<'a, ByteStr> { impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] fn from(s: &'a ByteString) -> Self { - Cow::Borrowed(s.as_bytestr()) + Cow::Borrowed(s.as_byte_str()) } } @@ -288,11 +583,11 @@ impl<'a> FromIterator<&'a str> for ByteString { impl<'a> FromIterator<&'a [u8]> for ByteString { #[inline] fn from_iter>(iter: T) -> Self { - let mut buf = Vec::new(); + let mut buf = ByteString::new(); for b in iter { - buf.extend_from_slice(b); + buf.push(ByteStr::new(b)); } - ByteString(buf) + buf } } @@ -300,11 +595,11 @@ impl<'a> FromIterator<&'a [u8]> for ByteString { impl<'a> FromIterator<&'a ByteStr> for ByteString { #[inline] fn from_iter>(iter: T) -> Self { - let mut buf = Vec::new(); + let mut buf = ByteString::new(); for b in iter { - buf.extend_from_slice(&b.0); + buf.push(b); } - ByteString(buf) + buf } } @@ -346,7 +641,7 @@ impl Index for ByteString { #[inline] fn index(&self, _: RangeFull) -> &ByteStr { - self.as_bytestr() + self.as_byte_str() } } @@ -356,7 +651,7 @@ impl Index> for ByteString { #[inline] fn index(&self, r: Range) -> &ByteStr { - ByteStr::from_bytes(&self.0[r]) + ByteStr::new(&self.0[r]) } } @@ -366,7 +661,7 @@ impl Index> for ByteString { #[inline] fn index(&self, r: RangeInclusive) -> &ByteStr { - ByteStr::from_bytes(&self.0[r]) + ByteStr::new(&self.0[r]) } } @@ -376,7 +671,7 @@ impl Index> for ByteString { #[inline] fn index(&self, r: RangeFrom) -> &ByteStr { - ByteStr::from_bytes(&self.0[r]) + ByteStr::new(&self.0[r]) } } @@ -386,7 +681,7 @@ impl Index> for ByteString { #[inline] fn index(&self, r: RangeTo) -> &ByteStr { - ByteStr::from_bytes(&self.0[r]) + ByteStr::new(&self.0[r]) } } @@ -396,7 +691,7 @@ impl Index> for ByteString { #[inline] fn index(&self, r: RangeToInclusive) -> &ByteStr { - ByteStr::from_bytes(&self.0[r]) + ByteStr::new(&self.0[r]) } } @@ -412,7 +707,7 @@ impl IndexMut for ByteString { impl IndexMut for ByteString { #[inline] fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { - self.as_mut_bytestr() + self.as_mut_byte_str() } } @@ -420,7 +715,7 @@ impl IndexMut for ByteString { impl IndexMut> for ByteString { #[inline] fn index_mut(&mut self, r: Range) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0[r]) + ByteStr::new_mut(&mut self.0[r]) } } @@ -428,7 +723,7 @@ impl IndexMut> for ByteString { impl IndexMut> for ByteString { #[inline] fn index_mut(&mut self, r: RangeInclusive) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0[r]) + ByteStr::new_mut(&mut self.0[r]) } } @@ -436,7 +731,7 @@ impl IndexMut> for ByteString { impl IndexMut> for ByteString { #[inline] fn index_mut(&mut self, r: RangeFrom) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0[r]) + ByteStr::new_mut(&mut self.0[r]) } } @@ -444,7 +739,7 @@ impl IndexMut> for ByteString { impl IndexMut> for ByteString { #[inline] fn index_mut(&mut self, r: RangeTo) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0[r]) + ByteStr::new_mut(&mut self.0[r]) } } @@ -452,7 +747,7 @@ impl IndexMut> for ByteString { impl IndexMut> for ByteString { #[inline] fn index_mut(&mut self, r: RangeToInclusive) -> &mut ByteStr { - ByteStr::from_bytes_mut(&mut self.0[r]) + ByteStr::new_mut(&mut self.0[r]) } } @@ -563,7 +858,7 @@ impl ToOwned for ByteStr { #[inline] fn to_owned(&self) -> ByteString { - ByteString(self.0.to_vec()) + self.to_byte_string() } } @@ -593,7 +888,7 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { impl Clone for Box { #[inline] fn clone(&self) -> Self { - Self::from(Box::<[u8]>::from(&self.0)) + Self::from(Box::<[u8]>::from(self.as_bytes())) } } @@ -677,6 +972,6 @@ impl<'a> TryFrom<&'a ByteStr> for String { #[inline] fn try_from(s: &'a ByteStr) -> Result { - Ok(core::str::from_utf8(&s.0)?.into()) + Ok(core::str::from_utf8(s.as_bytes())?.into()) } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index a83b51ccb60c3..0551cf0a0cad0 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -11,6 +11,8 @@ use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] +use core::bstr::ByteStr; +#[cfg(not(no_global_oom_handling))] use core::clone::TrivialClone; #[cfg(not(no_global_oom_handling))] use core::cmp::Ordering::{self, Less}; @@ -661,6 +663,16 @@ impl [u8] { me.make_ascii_lowercase(); me } + + /// Converts a `Box<[u8]>` into a `Box` without copying or allocating. + #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + pub fn into_boxed_byte_str(self: Box<[u8]>) -> Box { + // SAFETY: `ByteStr` is a thin wrapper over `[u8]` + unsafe { Box::from_raw(Box::into_raw(self) as _) } + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 43a68ff203738..ab1489c8049dd 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -93,6 +93,8 @@ pub use self::extract_if::ExtractIf; use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; +#[cfg(not(no_global_oom_handling))] +use crate::bstr::ByteString; use crate::collections::TryReserveError; use crate::raw_vec::RawVec; @@ -3350,6 +3352,17 @@ impl Vec { } } +#[cfg(not(no_global_oom_handling))] +impl Vec { + /// Converts a vector of bytes into a byte string. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn into_byte_string(self) -> ByteString { + ByteString(self) + } +} + impl Vec<[T; N], A> { /// Takes a `Vec<[T; N]>` and flattens it into a `Vec`. /// diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index e13dc5cd44d5c..0874820f27768 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -6,8 +6,8 @@ mod traits; pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; use crate::borrow::{Borrow, BorrowMut}; -use crate::fmt; -use crate::ops::{Deref, DerefMut, DerefPure}; +use crate::marker::Destruct; +use crate::{fmt, str}; /// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not /// always, UTF-8. @@ -40,7 +40,8 @@ use crate::ops::{Deref, DerefMut, DerefPure}; #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[doc(alias = "BStr")] -pub struct ByteStr(pub [u8]); +#[rustc_has_incoherent_inherent_impls] +pub struct ByteStr(pub(crate) [u8]); impl ByteStr { /// Creates a `ByteStr` slice from anything that can be converted to a byte slice. @@ -52,8 +53,9 @@ impl ByteStr { /// You can create a `ByteStr` from a byte array, a byte slice or a string slice: /// /// ``` - /// # #![feature(bstr)] - /// # use std::bstr::ByteStr; + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// /// let a = ByteStr::new(b"abc"); /// let b = ByteStr::new(&b"abc"[..]); /// let c = ByteStr::new("abc"); @@ -68,71 +70,273 @@ impl ByteStr { ByteStr::from_bytes(bytes.as_ref()) } - #[doc(hidden)] - #[unstable(feature = "bstr_internals", issue = "none")] + /// Creates a mutable `ByteStr` slice from anything that can be converted to a mutable byte slice. + /// + /// This is a zero-cost conversion. + /// + /// # Example + /// + /// Unlike `str`, the raw bytes of a `ByteStr` can be safely mutated at any time, since the + /// result is not guaranteed to be valid UTF-8. + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let mut buf = "😀".to_string().into_bytes().into_byte_string(); + /// assert_eq!(format!("{buf}"), "😀"); + /// + /// let s = ByteStr::new_mut(&mut buf); + /// s.as_bytes_mut().reverse(); + /// s[1] = b':'; + /// s[2] = b'('; + /// + /// assert_eq!(format!("{buf}"), "�:(�"); + /// ``` #[inline] - #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] - pub const fn from_bytes(slice: &[u8]) -> &Self { + #[unstable(feature = "bstr", issue = "134915")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new_mut>(bytes: &mut B) -> &mut Self { + ByteStr::from_bytes_mut(bytes.as_mut()) + } + + #[inline] + pub(crate) const fn from_bytes(slice: &[u8]) -> &Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &*(slice as *const [u8] as *const Self) } } - #[doc(hidden)] - #[unstable(feature = "bstr_internals", issue = "none")] #[inline] - #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] - pub const fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { + pub(crate) const fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &mut *(slice as *mut [u8] as *mut Self) } } - #[doc(hidden)] - #[unstable(feature = "bstr_internals", issue = "none")] + /// Converts a `ByteStr` slice to a byte slice. To convert the byte slice back into a byte string + /// slice, use [`ByteStr::new`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let s = ByteStr::new("bors"); + /// let bytes = s.as_bytes(); + /// assert_eq!(b"bors", bytes); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] #[inline] - #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] pub const fn as_bytes(&self) -> &[u8] { &self.0 } - #[doc(hidden)] - #[unstable(feature = "bstr_internals", issue = "none")] + /// Converts a mutable `ByteStr` slice to a mutable byte slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let mut s = ByteStr::new("Hello").to_byte_string(); + /// let bytes = s.as_bytes_mut(); + /// assert_eq!(b"Hello", bytes); + /// ``` + /// + /// Mutability: + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let mut s = ByteStr::new("🗻∈🌏").to_byte_string(); + /// let bytes = s.as_bytes_mut(); + /// + /// bytes[0] = 0xF0; + /// bytes[1] = 0x9F; + /// bytes[2] = 0x8D; + /// bytes[3] = 0x94; + /// + /// assert_eq!("🍔∈🌏", s); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] #[inline] - #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] pub const fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.0 } -} -#[unstable(feature = "bstr", issue = "134915")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const Deref for ByteStr { - type Target = [u8]; + /// Yields a &[prim@str] slice if the `ByteStr` is valid unicode. + /// + /// This conversion may entail a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let bstr = ByteStr::new("foo"); + /// assert_eq!(bstr.to_str(), Some("foo")); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn to_str(&self) -> Option<&str> { + str::from_utf8(&self.0).ok() + } + /// Checks whether the `ByteStr` is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let byte_str = ByteStr::new(""); + /// assert!(byte_str.is_empty()); + /// + /// let byte_str = ByteStr::new("foo"); + /// assert!(!byte_str.is_empty()); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] #[inline] - fn deref(&self) -> &[u8] { - &self.0 + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn is_empty(&self) -> bool { + self.0.is_empty() } -} -#[unstable(feature = "bstr", issue = "134915")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const DerefMut for ByteStr { + /// Returns the length of this `ByteStr` in bytes. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let byte_str = ByteStr::new(""); + /// assert_eq!(byte_str.len(), 0); + /// + /// let byte_str = ByteStr::new("foo"); + /// assert_eq!(byte_str.len(), 3); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - &mut self.0 + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn len(&self) -> usize { + self.0.len() + } + + /// Checks if all bytes in this byte string are within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let ascii = ByteStr::new("hello!\n"); + /// let non_ascii = ByteStr::new("Grüße, Jürgen ❤"); + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn is_ascii(&self) -> bool { + self.0.is_ascii() + } + + /// Converts this byte string to its ASCII lower case equivalent in-place. + /// + /// ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters are unchanged. + /// To return a new lowercased value without modifying the existing one, use + /// `ByteStr::to_ascii_lowercase`. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let mut s = ByteStr::new("GRÜßE, JÜRGEN ❤").to_byte_string(); + /// + /// s.make_ascii_lowercase(); + /// + /// assert_eq!("grÜße, jÜrgen ❤", s); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn make_ascii_lowercase(&mut self) { + self.0.make_ascii_lowercase() + } + + /// Converts this byte string to its ASCII upper case equivalent in-place. + /// + /// ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters are unchanged. + /// To return a new uppercased value without modifying the existing one, use + /// `ByteStr::to_ascii_uppercase`. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// let mut s = ByteStr::new("Grüße, Jürgen ❤").to_byte_string(); + /// + /// s.make_ascii_uppercase(); + /// + /// assert_eq!("GRüßE, JüRGEN ❤", s); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn make_ascii_uppercase(&mut self) { + self.0.make_ascii_uppercase() } -} -#[unstable(feature = "deref_pure_trait", issue = "87121")] -unsafe impl DerefPure for ByteStr {} + /// Checks if two byte strings are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, but without allocating and copying + /// temporaries. + /// + /// # Examples + /// + /// ``` + /// #![feature(bstr)] + /// use std::bstr::ByteStr; + /// + /// assert!(ByteStr::new("Ferris").eq_ignore_ascii_case("FERRIS")); + /// assert!(ByteStr::new("Ferrös").eq_ignore_ascii_case("FERRöS")); + /// assert!(!ByteStr::new("Ferrös").eq_ignore_ascii_case("FERRÖS")); + /// ``` + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn eq_ignore_ascii_case + [const] Destruct>( + &self, + other: S, + ) -> bool { + let other: &ByteStr = other.as_ref(); + self.0.eq_ignore_ascii_case(&other.0) + } +} #[unstable(feature = "bstr", issue = "134915")] impl fmt::Debug for ByteStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\"")?; - for chunk in self.utf8_chunks() { + for chunk in self.0.utf8_chunks() { for c in chunk.valid().chars() { match c { '\0' => write!(f, "\\0")?, @@ -151,7 +355,7 @@ impl fmt::Debug for ByteStr { impl fmt::Display for ByteStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for chunk in this.utf8_chunks() { + for chunk in this.0.utf8_chunks() { f.write_str(chunk.valid())?; if !chunk.invalid().is_empty() { f.write_str("\u{FFFD}")?; @@ -164,6 +368,7 @@ impl fmt::Display for ByteStr { return fmt_nopad(self, f); }; let nchars: usize = self + .0 .utf8_chunks() .map(|chunk| { chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } @@ -318,21 +523,21 @@ impl<'a> Default for &'a mut ByteStr { #[unstable(feature = "bstr", issue = "134915")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<'a> const TryFrom<&'a ByteStr> for &'a str { - type Error = crate::str::Utf8Error; + type Error = str::Utf8Error; #[inline] fn try_from(s: &'a ByteStr) -> Result { - crate::str::from_utf8(&s.0) + str::from_utf8(&s.0) } } #[unstable(feature = "bstr", issue = "134915")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<'a> const TryFrom<&'a mut ByteStr> for &'a mut str { - type Error = crate::str::Utf8Error; + type Error = str::Utf8Error; #[inline] fn try_from(s: &'a mut ByteStr) -> Result { - crate::str::from_utf8_mut(&mut s.0) + str::from_utf8_mut(&mut s.0) } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f03f2045444df..ca6c6a62d4054 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -6,6 +6,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::bstr::ByteStr; use crate::clone::TrivialClone; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; @@ -4908,6 +4909,24 @@ impl [T] { } } +impl [u8] { + /// Casts a byte slice as a byte string. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn as_byte_str(&self) -> &ByteStr { + ByteStr::from_bytes(self) + } + + /// Casts a mutable byte slice as a byte string. + #[unstable(feature = "bstr", issue = "134915")] + #[inline] + #[rustc_const_unstable(feature = "bstr", issue = "134915")] + pub const fn as_mut_byte_str(&mut self) -> &mut ByteStr { + ByteStr::from_bytes_mut(self) + } +} + impl [MaybeUninit] { /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of /// another type, ensuring alignment of the types is maintained. diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 25b95014e08b2..d681a45f76947 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -246,7 +246,7 @@ impl SocketAddr { { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) + AddressKind::Abstract(ByteStr::new(&path[1..len])) } else { AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) } diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index 71a1360cb5a22..f91311075a7df 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -31,9 +31,6 @@ LL | type X = std::ops::Deref::Target; help: use fully-qualified syntax | LL - type X = std::ops::Deref::Target; -LL + type X = ::Target; - | -LL - type X = std::ops::Deref::Target; LL + type X = ::Target; | LL - type X = std::ops::Deref::Target; @@ -42,6 +39,9 @@ LL + type X = ::Target; LL - type X = std::ops::Deref::Target; LL + type X = as Deref>::Target; | +LL - type X = std::ops::Deref::Target; +LL + type X = as Deref>::Target; + | = and N other candidates error[E0223]: ambiguous associated type