From 2808977e053c47c8fee731432f9c91a8581fad96 Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Thu, 2 Jan 2025 22:37:03 +0200 Subject: [PATCH 1/8] Implement `ByteStr` and `ByteString` types Approved ACP: https://github.com/rust-lang/libs-team/issues/502 Tracking issue: https://github.com/rust-lang/rust/issues/134915 These types represent human-readable strings that are conventionally, but not always, UTF-8. The `Debug` impl prints non-UTF-8 bytes using escape sequences, and the `Display` impl uses the Unicode replacement character. This is a minimal implementation of these types and associated trait impls. It does not add any helper methods to other types such as `[u8]` or `Vec<u8>`. I've omitted a few implementations of `AsRef`, `AsMut`, `Borrow`, `From`, and `PartialOrd`, when those would be the second implementation for a type (counting the `T` impl) or otherwise may cause inference failures. These impls are important, but we can attempt to add them later in standalone commits, and run them through crater. In addition to the `bstr` feature, I've added a `bstr_internals` feature for APIs provided by `core` for use by `alloc` but not currently intended for stabilization. This API and its implementation are based *heavily* on the `bstr` crate by Andrew Gallant (@BurntSushi). --- library/alloc/src/bstr.rs | 683 +++++++++++++++++++++++++++++++++++++ library/alloc/src/lib.rs | 4 + library/core/src/bstr.rs | 576 +++++++++++++++++++++++++++++++ library/core/src/lib.rs | 4 + library/core/tests/bstr.rs | 54 +++ library/std/src/bstr.rs | 4 + library/std/src/lib.rs | 4 + 7 files changed, 1329 insertions(+) create mode 100644 library/alloc/src/bstr.rs create mode 100644 library/core/src/bstr.rs create mode 100644 library/core/tests/bstr.rs create mode 100644 library/std/src/bstr.rs diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs new file mode 100644 index 0000000000000..c27c6afb55853 --- /dev/null +++ b/library/alloc/src/bstr.rs @@ -0,0 +1,683 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +use core::borrow::{Borrow, BorrowMut}; +#[unstable(feature = "bstr", issue = "134915")] +pub use core::bstr::ByteStr; +use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; +use core::cmp::Ordering; +use core::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +use core::str::FromStr; +use core::{fmt, hash}; + +use crate::borrow::{Cow, ToOwned}; +use crate::boxed::Box; +use crate::rc::Rc; +use crate::string::String; +use crate::sync::Arc; +use crate::vec::Vec; + +/// A wrapper for `Vec<u8>` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a +/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html). +/// +/// `ByteString` implements `Deref` to `&Vec<u8>`, so all methods available on `&Vec<u8>` are +/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec<u8>`, +/// so you can modify a `ByteString` using any method available on `&mut Vec<u8>`. +/// +/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`, +/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. +/// +/// # Examples +/// +/// You can create a new `ByteString` from a `Vec<u8>` directly, or via a `From` impl from various +/// string types: +/// +/// ``` +/// # #![feature(bstr)] +/// # use std::bstr::ByteString; +/// let s1 = ByteString(vec![b'H', b'e', b'l', b'l', b'o']); +/// let s2 = ByteString::from("Hello"); +/// let s3 = ByteString::from(b"Hello"); +/// assert_eq!(s1, s2); +/// assert_eq!(s2, s3); +/// ``` +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +#[derive(Clone)] +pub struct ByteString(pub Vec<u8>); + +impl ByteString { + #[inline] + pub(crate) fn as_bytes(&self) -> &[u8] { + &self.0 + } + + #[inline] + pub(crate) fn as_bytestr(&self) -> &ByteStr { + ByteStr::new(&self.0) + } + + #[inline] + pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteString { + type Target = Vec<u8>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteString { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Debug for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Display for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteString { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for ByteString { + #[inline] + fn as_ref(&self) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<ByteStr> for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteString { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<ByteStr> for ByteString { + #[inline] + fn borrow(&self) -> &ByteStr { + self.as_bytestr() + } +} + +// `impl Borrow<ByteStr> for Vec<u8>` omitted to avoid inference failures +// `impl Borrow<ByteStr> for String` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<ByteStr> for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +// `impl BorrowMut<ByteStr> for Vec<u8>` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Default for ByteString { + fn default() -> Self { + ByteString(Vec::new()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { + #[inline] + fn from(s: &'a [u8; N]) -> Self { + ByteString(s.as_slice().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<const N: usize> From<[u8; N]> for ByteString { + #[inline] + fn from(s: [u8; N]) -> Self { + ByteString(s.as_slice().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a [u8]> for ByteString { + #[inline] + fn from(s: &'a [u8]) -> Self { + ByteString(s.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Vec<u8>> for ByteString { + #[inline] + fn from(s: Vec<u8>) -> Self { + ByteString(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<ByteString> for Vec<u8> { + #[inline] + fn from(s: ByteString) -> Self { + s.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a str> for ByteString { + #[inline] + fn from(s: &'a str) -> Self { + ByteString(s.as_bytes().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<String> for ByteString { + #[inline] + fn from(s: String) -> Self { + ByteString(s.into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for ByteString { + #[inline] + fn from(s: &'a ByteStr) -> Self { + ByteString(s.0.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<ByteString> for Cow<'a, ByteStr> { + #[inline] + fn from(s: ByteString) -> Self { + Cow::Owned(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteString) -> Self { + Cow::Borrowed(s.as_bytestr()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<char> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self { + ByteString(iter.into_iter().collect::<String>().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<u8> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self { + ByteString(iter.into_iter().collect()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a str> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { + ByteString(iter.into_iter().collect::<String>().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a [u8]> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(b); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a ByteStr> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a ByteStr>>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(&b.0); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<ByteString> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = ByteString>>(iter: T) -> Self { + let mut buf = Vec::new(); + for mut b in iter { + buf.append(&mut b.0); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromStr for ByteString { + type Err = core::convert::Infallible; + + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(ByteString(s.as_bytes().to_vec())) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<usize> for ByteString { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFull> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<Range<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeInclusive<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFrom<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeTo<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeToInclusive<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<usize> for ByteString { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFull> for ByteString { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<Range<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeInclusive<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFrom<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeTo<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeToInclusive<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteString { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq for ByteString { + #[inline] + fn eq(&self, other: &ByteString) -> bool { + self.0 == other.0 + } +} + +macro_rules! impl_partial_eq_ord_cow { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = (&**other).as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = (&**self).as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { + let other: &[u8] = (&**other).as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { + let this: &[u8] = (&**self).as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +// PartialOrd with `Vec<u8>` omitted to avoid inference failures +impl_partial_eq!(ByteString, Vec<u8>); +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, &[u8]); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteString, String); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteString, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteString, &str); +impl_partial_eq_ord!(ByteString, ByteStr); +impl_partial_eq_ord!(ByteString, &ByteStr); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, [u8; N]); +// PartialOrd with `&[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, &[u8; N]); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteString { + #[inline] + fn cmp(&self, other: &ByteString) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteString { + #[inline] + fn partial_cmp(&self, other: &ByteString) -> Option<Ordering> { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl ToOwned for ByteStr { + type Owned = ByteString; + + #[inline] + fn to_owned(&self) -> ByteString { + ByteString(self.0.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl TryFrom<ByteString> for String { + type Error = crate::string::FromUtf8Error; + + #[inline] + fn try_from(s: ByteString) -> Result<Self, Self::Error> { + String::from_utf8(s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteString> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteString) -> Result<Self, Self::Error> { + crate::str::from_utf8(s.0.as_slice()) + } +} + +// Additional impls for `ByteStr` that require types from `alloc`: + +#[unstable(feature = "bstr", issue = "134915")] +impl Clone for Box<ByteStr> { + #[inline] + fn clone(&self) -> Self { + Self::from(Box::<[u8]>::from(&self.0)) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteStr) -> Self { + Cow::Borrowed(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Box<[u8]>> for Box<ByteStr> { + #[inline] + fn from(s: Box<[u8]>) -> Box<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Box<ByteStr>> for Box<[u8]> { + #[inline] + fn from(s: Box<ByteStr>) -> Box<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Rc<[u8]>> for Rc<ByteStr> { + #[inline] + fn from(s: Rc<[u8]>) -> Rc<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Rc<ByteStr>> for Rc<[u8]> { + #[inline] + fn from(s: Rc<ByteStr>) -> Rc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Arc<[u8]>> for Arc<ByteStr> { + #[inline] + fn from(s: Arc<[u8]>) -> Arc<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<Arc<ByteStr>> for Arc<[u8]> { + #[inline] + fn from(s: Arc<ByteStr>) -> Arc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +// PartialOrd with `Vec<u8>` omitted to avoid inference failures +impl_partial_eq!(ByteStr, Vec<u8>); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteStr, String); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for String { + type Error = core::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> { + Ok(core::str::from_utf8(&s.0)?.into()) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 784af9407692a..f9e91fbc8a566 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -102,6 +102,8 @@ #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_uninit_write)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_eval_select)] @@ -226,6 +228,8 @@ mod boxed { pub use std::boxed::Box; } pub mod borrow; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] pub mod ffi; diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs new file mode 100644 index 0000000000000..11212761eadd7 --- /dev/null +++ b/library/core/src/bstr.rs @@ -0,0 +1,576 @@ +//! The `ByteStr` type and trait implementations. + +use crate::borrow::{Borrow, BorrowMut}; +use crate::cmp::Ordering; +use crate::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +use crate::{fmt, hash}; + +/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// For an owned, growable byte string buffer, use +/// [`ByteString`](../../std/bstr/struct.ByteString.html). +/// +/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on +/// `ByteStr`. +/// +/// # Representation +/// +/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer +/// which includes a pointer to some bytes and a length. +/// +/// # Trait implementations +/// +/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality +/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience. +/// +/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. +/// +/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a +/// `str`, with invalid UTF-8 presented as the Unicode replacement character: � +/// +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +pub struct ByteStr(pub [u8]); + +impl ByteStr { + /// Creates a `ByteStr` slice from anything that can be converted to a byte slice. + /// + /// This is a zero-cost conversion. + /// + /// # Example + /// + /// You can create a `ByteStr` from a byte array, a byte slice or a string slice: + /// + /// ``` + /// # #![feature(bstr)] + /// # use std::bstr::ByteStr; + /// let a = ByteStr::new(b"abc"); + /// let b = ByteStr::new(&b"abc"[..]); + /// let c = ByteStr::new("abc"); + /// + /// assert_eq!(a, b); + /// assert_eq!(a, c); + /// ``` + #[inline] + #[unstable(feature = "bstr", issue = "134915")] + pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self { + ByteStr::from_bytes(bytes.as_ref()) + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub 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] + pub 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")] + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteStr { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteStr { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteStr {} + +#[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 c in chunk.valid().chars() { + match c { + '\0' => write!(f, "\\0")?, + '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?, + _ => write!(f, "{}", c.escape_debug())?, + } + } + write!(f, "{}", chunk.invalid().escape_ascii())?; + } + write!(f, "\"")?; + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +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() { + f.write_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + f.write_str("\u{FFFD}")?; + } + } + Ok(()) + } + + let Some(align) = f.align() else { + return fmt_nopad(self, f); + }; + let nchars: usize = self + .utf8_chunks() + .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 }) + .sum(); + let padding = f.width().unwrap_or(0).saturating_sub(nchars); + let fill = f.fill(); + let (lpad, rpad) = match align { + fmt::Alignment::Left => (0, padding), + fmt::Alignment::Right => (padding, 0), + fmt::Alignment::Center => { + let half = padding / 2; + (half, half + padding % 2) + } + }; + for _ in 0..lpad { + write!(f, "{fill}")?; + } + fmt_nopad(self, f)?; + for _ in 0..rpad { + write!(f, "{fill}")?; + } + + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteStr { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for ByteStr { + #[inline] + fn as_ref(&self) -> &ByteStr { + self + } +} + +// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for str { + #[inline] + fn as_ref(&self) -> &ByteStr { + ByteStr::new(self) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteStr { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteStr { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a ByteStr { + fn default() -> Self { + ByteStr::from_bytes(b"") + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a mut ByteStr { + fn default() -> Self { + ByteStr::from_bytes_mut(&mut []) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { + #[inline] + fn from(s: &'a [u8; N]) -> Self { + ByteStr::from_bytes(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a [u8]> for &'a ByteStr { + #[inline] + fn from(s: &'a [u8]) -> Self { + ByteStr::from_bytes(s) + } +} + +// Omitted due to slice-from-array-issue-113238: +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a ByteStr> for &'a [u8] { +// #[inline] +// fn from(s: &'a ByteStr) -> Self { +// &s.0 +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] { +// #[inline] +// fn from(s: &'a mut ByteStr) -> Self { +// &mut s.0 +// } +// } + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a str> for &'a ByteStr { + #[inline] + fn from(s: &'a str) -> Self { + ByteStr::from_bytes(s.as_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteStr { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<usize> for ByteStr { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFull> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<Range<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeInclusive<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFrom<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeTo<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeToInclusive<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<usize> for ByteStr { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFull> for ByteStr { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<Range<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeInclusive<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFrom<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeTo<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeToInclusive<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteStr {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq<ByteStr> for ByteStr { + #[inline] + fn eq(&self, other: &ByteStr) -> bool { + &self.0 == &other.0 + } +} + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_ord { + ($lhs:ty, $rhs:ty) => { + $crate::bstr::impl_partial_eq!($lhs, $rhs); + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { + let other: &[u8] = other.as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { + let this: &[u8] = self.as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_ord; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_n { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<const N: usize> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<const N: usize> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_n; + +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &[u8]); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &str); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, [u8; N]); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, &[u8; N]); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteStr { + #[inline] + fn cmp(&self, other: &ByteStr) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteStr { + #[inline] + fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> { + crate::str::from_utf8(&s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> { + crate::str::from_utf8_mut(&mut s.0) + } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e845bb34426c4..2626fbdd77629 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -110,6 +110,8 @@ #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -335,6 +337,8 @@ pub mod ascii; pub mod asserting; #[unstable(feature = "async_iterator", issue = "79024")] pub mod async_iter; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod cell; pub mod char; pub mod ffi; diff --git a/library/core/tests/bstr.rs b/library/core/tests/bstr.rs new file mode 100644 index 0000000000000..5fecd0a4084c7 --- /dev/null +++ b/library/core/tests/bstr.rs @@ -0,0 +1,54 @@ +#![feature(bstr)] + +use core::ByteStr; + +#[test] +fn test_debug() { + assert_eq!( + r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#, + format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")), + ); +} + +#[test] +fn test_display() { + let b1 = ByteStr::new("abc"); + let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc"); + + assert_eq!(&format!("{b1}"), "abc"); + assert_eq!(&format!("{b2}"), "�(��"); + + assert_eq!(&format!("{b1:<7}!"), "abc !"); + assert_eq!(&format!("{b1:>7}!"), " abc!"); + assert_eq!(&format!("{b1:^7}!"), " abc !"); + assert_eq!(&format!("{b1:^6}!"), " abc !"); + assert_eq!(&format!("{b1:-<7}!"), "abc----!"); + assert_eq!(&format!("{b1:->7}!"), "----abc!"); + assert_eq!(&format!("{b1:-^7}!"), "--abc--!"); + assert_eq!(&format!("{b1:-^6}!"), "-abc--!"); + + assert_eq!(&format!("{b2:<7}!"), "�(�� !"); + assert_eq!(&format!("{b2:>7}!"), " �(��!"); + assert_eq!(&format!("{b2:^7}!"), " �(�� !"); + assert_eq!(&format!("{b2:^6}!"), " �(�� !"); + assert_eq!(&format!("{b2:-<7}!"), "�(��---!"); + assert_eq!(&format!("{b2:->7}!"), "---�(��!"); + assert_eq!(&format!("{b2:-^7}!"), "-�(��--!"); + assert_eq!(&format!("{b2:-^6}!"), "-�(��-!"); + + assert_eq!(&format!("{b1:<2}!"), "abc!"); + assert_eq!(&format!("{b1:>2}!"), "abc!"); + assert_eq!(&format!("{b1:^2}!"), "abc!"); + assert_eq!(&format!("{b1:-<2}!"), "abc!"); + assert_eq!(&format!("{b1:->2}!"), "abc!"); + assert_eq!(&format!("{b1:-^2}!"), "abc!"); + + assert_eq!(&format!("{b2:<3}!"), "�(��!"); + assert_eq!(&format!("{b2:>3}!"), "�(��!"); + assert_eq!(&format!("{b2:^3}!"), "�(��!"); + assert_eq!(&format!("{b2:^2}!"), "�(��!"); + assert_eq!(&format!("{b2:-<3}!"), "�(��!"); + assert_eq!(&format!("{b2:->3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^2}!"), "�(��!"); +} diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs new file mode 100644 index 0000000000000..dd49177162833 --- /dev/null +++ b/library/std/src/bstr.rs @@ -0,0 +1,4 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +#[unstable(feature = "bstr", issue = "134915")] +pub use alloc::bstr::{ByteStr, ByteString}; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2f8f5c5c58180..7560bab6d5dbc 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -320,6 +320,8 @@ // Library features (core): // tidy-alphabetical-start #![feature(array_chunks)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -580,6 +582,8 @@ pub mod f64; pub mod thread; pub mod ascii; pub mod backtrace; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; pub mod env; pub mod error; From dcc352f341485c99d02bfd947362b925db0aa6ca Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Sat, 4 Jan 2025 14:48:48 +0200 Subject: [PATCH 2/8] Bless new test output (new trait impls in lists of suggestions) --- .../associated-types-in-ambiguous-context.stderr | 8 ++++---- tests/ui/consts/too_generic_eval_ice.stderr | 10 +++++----- tests/ui/inference/issue-72616.stderr | 13 ++++++++----- tests/ui/inference/issue-72690.stderr | 9 +++++++++ 4 files changed, 26 insertions(+), 14 deletions(-) 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 c5260adbed43a..88db361171919 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -40,14 +40,14 @@ LL | type X = std::ops::Deref::Target; | help: use fully-qualified syntax | +LL | type X = <ByteStr as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type X = <ByteString as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | type X = <CString as Deref>::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | type X = <IoSlice<'_> as Deref>::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | type X = <IoSliceMut<'_> as Deref>::Target; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | type X = <OsString as Deref>::Target; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ and N other candidates error: aborting due to 5 previous errors diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index b48be16a24c8e..3cc4377514a21 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -32,13 +32,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = help: the following other types implement trait `PartialEq<Rhs>`: `&[T]` implements `PartialEq<Vec<U, A>>` `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq<ByteStr>` + `&[u8; N]` implements `PartialEq<ByteString>` + `&[u8]` implements `PartialEq<ByteStr>` + `&[u8]` implements `PartialEq<ByteString>` `&mut [T]` implements `PartialEq<Vec<U, A>>` `&mut [T]` implements `PartialEq<[U; N]>` - `[T; N]` implements `PartialEq<&[U]>` - `[T; N]` implements `PartialEq<&mut [U]>` - `[T; N]` implements `PartialEq<[U; N]>` - `[T; N]` implements `PartialEq<[U]>` - and 3 others + and 11 others error: aborting due to 4 previous errors diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr index 02c92c1c11d02..a26f9a1ff5618 100644 --- a/tests/ui/inference/issue-72616.stderr +++ b/tests/ui/inference/issue-72616.stderr @@ -6,11 +6,14 @@ LL | if String::from("a") == "a".try_into().unwrap() {} | | | type must be known at this point | - = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate: - - impl PartialEq for String; - - impl<'a, 'b> PartialEq<&'a str> for String; - - impl<'a, 'b> PartialEq<Cow<'a, str>> for String; - - impl<'a, 'b> PartialEq<str> for String; + = note: cannot satisfy `String: PartialEq<_>` + = help: the following types implement trait `PartialEq<Rhs>`: + `String` implements `PartialEq<&str>` + `String` implements `PartialEq<ByteStr>` + `String` implements `PartialEq<ByteString>` + `String` implements `PartialEq<Cow<'_, str>>` + `String` implements `PartialEq<str>` + `String` implements `PartialEq` help: try using a fully qualified path to specify the expected types | LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {} diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr index 6391672f8617d..2d09f667ae2cf 100644 --- a/tests/ui/inference/issue-72690.stderr +++ b/tests/ui/inference/issue-72690.stderr @@ -15,6 +15,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -41,6 +42,7 @@ LL | |x| String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -57,6 +59,7 @@ LL | let _ = "x".as_ref(); | ^ ------ type must be known at this point | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -83,6 +86,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -109,6 +113,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -135,6 +140,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -161,6 +167,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -187,6 +194,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -213,6 +221,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; From fc34bea69db2294413b3ecea5edd1f12c70c0f8b Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Sat, 4 Jan 2025 16:08:20 +0200 Subject: [PATCH 3/8] Add `#[cfg(not(test))]` to some impls to work around https://github.com/rust-lang/rust/issues/135100 --- library/alloc/src/bstr.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index c27c6afb55853..a447ab38d17cc 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -9,10 +9,13 @@ use core::ops::{ Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use core::str::FromStr; use core::{fmt, hash}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::borrow::{Cow, ToOwned}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; use crate::rc::Rc; use crate::string::String; @@ -185,6 +188,7 @@ impl Default for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { #[inline] @@ -193,6 +197,7 @@ impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<const N: usize> From<[u8; N]> for ByteString { #[inline] @@ -201,6 +206,7 @@ impl<const N: usize> From<[u8; N]> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a [u8]> for ByteString { #[inline] @@ -225,6 +231,7 @@ impl From<ByteString> for Vec<u8> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a str> for ByteString { #[inline] @@ -241,6 +248,7 @@ impl From<String> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for ByteString { #[inline] @@ -249,6 +257,7 @@ impl<'a> From<&'a ByteStr> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<ByteString> for Cow<'a, ByteStr> { #[inline] @@ -257,6 +266,7 @@ impl<'a> From<ByteString> for Cow<'a, ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] @@ -325,6 +335,7 @@ impl FromIterator<ByteString> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl FromStr for ByteString { type Err = core::convert::Infallible; @@ -482,6 +493,7 @@ impl PartialEq for ByteString { macro_rules! impl_partial_eq_ord_cow { ($lhs:ty, $rhs:ty) => { + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$rhs> for $lhs { @@ -492,6 +504,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$lhs> for $rhs { @@ -502,6 +515,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$rhs> for $lhs { @@ -512,6 +526,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$lhs> for $rhs { @@ -562,6 +577,7 @@ impl PartialOrd for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl ToOwned for ByteStr { type Owned = ByteString; @@ -594,6 +610,7 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { // Additional impls for `ByteStr` that require types from `alloc`: +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl Clone for Box<ByteStr> { #[inline] @@ -602,6 +619,7 @@ impl Clone for Box<ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { #[inline] @@ -610,6 +628,7 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From<Box<[u8]>> for Box<ByteStr> { #[inline] @@ -619,6 +638,7 @@ impl From<Box<[u8]>> for Box<ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From<Box<ByteStr>> for Box<[u8]> { #[inline] From 049217b65a1aebaa62c4ab9fe85fbff938961e7d Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Sun, 5 Jan 2025 16:51:49 +0200 Subject: [PATCH 4/8] Add bstr files to linkchecker since they have a Deref to slice The Deref brings in the documentation from slice, so it has the same issue as slice. --- src/tools/linkchecker/main.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 570b2c374c0e6..19340b5d07a11 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -50,6 +50,29 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/slice/trait.Concat.html", &["#method.concat"]), ("alloc/slice/index.html", &["#method.concat", "#method.join"]), ("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]), + ("alloc/bstr/struct.ByteStr.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/slice::sort_by_key", + "core\\slice::sort_by_key", + "#method.sort_by_cached_key", + "#method.sort_by_key" + ]), + ("alloc/bstr/struct.ByteString.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/slice::sort_by_key", + "core\\slice::sort_by_key", + "#method.sort_by_cached_key", + "#method.sort_by_key" + ]), + ("core/bstr/struct.ByteStr.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/bstr/slice::sort_by_key", + "core\\bstr\\slice::sort_by_key", + "#method.sort_by_cached_key" + ]), ("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]), ("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase", "core/slice::sort_by_key", "core\\slice::sort_by_key", From 76780fa10e9e449bdd68d773041f85a64303bb02 Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Mon, 6 Jan 2025 15:02:25 +0200 Subject: [PATCH 5/8] Support `no_rc`, `no_sync`, and `no_global_oom_handling` For now, apply `no_global_oom_handling` to all of library/alloc/src/bstr.rs . We can make it more fine-grained later. --- library/alloc/src/bstr.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index a447ab38d17cc..f16a36b0f9b52 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -1,5 +1,8 @@ //! The `ByteStr` and `ByteString` types and trait implementations. +// This could be more fine-grained. +#![cfg(not(no_global_oom_handling))] + use core::borrow::{Borrow, BorrowMut}; #[unstable(feature = "bstr", issue = "134915")] pub use core::bstr::ByteStr; @@ -17,8 +20,10 @@ use core::{fmt, hash}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; +#[cfg(not(no_rc))] use crate::rc::Rc; use crate::string::String; +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] use crate::sync::Arc; use crate::vec::Vec; @@ -649,6 +654,7 @@ impl From<Box<ByteStr>> for Box<[u8]> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] impl From<Rc<[u8]>> for Rc<ByteStr> { #[inline] fn from(s: Rc<[u8]>) -> Rc<ByteStr> { @@ -658,6 +664,7 @@ impl From<Rc<[u8]>> for Rc<ByteStr> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] impl From<Rc<ByteStr>> for Rc<[u8]> { #[inline] fn from(s: Rc<ByteStr>) -> Rc<[u8]> { @@ -667,6 +674,7 @@ impl From<Rc<ByteStr>> for Rc<[u8]> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] impl From<Arc<[u8]>> for Arc<ByteStr> { #[inline] fn from(s: Arc<[u8]>) -> Arc<ByteStr> { @@ -676,6 +684,7 @@ impl From<Arc<[u8]>> for Arc<ByteStr> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] impl From<Arc<ByteStr>> for Arc<[u8]> { #[inline] fn from(s: Arc<ByteStr>) -> Arc<[u8]> { From 22a4ec39fbb53fd39179961a19c643d600bbeebd Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Sun, 12 Jan 2025 12:27:24 +0200 Subject: [PATCH 6/8] Omit some more `From` impls to avoid inference failures --- library/alloc/src/bstr.rs | 119 +++++++++++++++++--------------------- library/core/src/bstr.rs | 48 ++++++++------- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index f16a36b0f9b52..acb60d9ca8618 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -43,21 +43,6 @@ use crate::vec::Vec; /// /// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`, /// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. -/// -/// # Examples -/// -/// You can create a new `ByteString` from a `Vec<u8>` directly, or via a `From` impl from various -/// string types: -/// -/// ``` -/// # #![feature(bstr)] -/// # use std::bstr::ByteString; -/// let s1 = ByteString(vec![b'H', b'e', b'l', b'l', b'o']); -/// let s2 = ByteString::from("Hello"); -/// let s3 = ByteString::from(b"Hello"); -/// assert_eq!(s1, s2); -/// assert_eq!(s2, s3); -/// ``` #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[derive(Clone)] @@ -193,40 +178,42 @@ impl Default for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { - #[inline] - fn from(s: &'a [u8; N]) -> Self { - ByteString(s.as_slice().to_vec()) - } -} - -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<const N: usize> From<[u8; N]> for ByteString { - #[inline] - fn from(s: [u8; N]) -> Self { - ByteString(s.as_slice().to_vec()) - } -} - -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a [u8]> for ByteString { - #[inline] - fn from(s: &'a [u8]) -> Self { - ByteString(s.to_vec()) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl From<Vec<u8>> for ByteString { - #[inline] - fn from(s: Vec<u8>) -> Self { - ByteString(s) - } -} +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<const N: usize> From<[u8; N]> for ByteString { +// #[inline] +// fn from(s: [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for ByteString { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteString(s.to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From<Vec<u8>> for ByteString { +// #[inline] +// fn from(s: Vec<u8>) -> Self { +// ByteString(s) +// } +// } #[unstable(feature = "bstr", issue = "134915")] impl From<ByteString> for Vec<u8> { @@ -236,22 +223,24 @@ impl From<ByteString> for Vec<u8> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a str> for ByteString { - #[inline] - fn from(s: &'a str) -> Self { - ByteString(s.as_bytes().to_vec()) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl From<String> for ByteString { - #[inline] - fn from(s: String) -> Self { - ByteString(s.into_bytes()) - } -} +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for ByteString { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteString(s.as_bytes().to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From<String> for ByteString { +// #[inline] +// fn from(s: String) -> Self { +// ByteString(s.into_bytes()) +// } +// } #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs index 11212761eadd7..9f20eb1a0e8ee 100644 --- a/library/core/src/bstr.rs +++ b/library/core/src/bstr.rs @@ -246,21 +246,23 @@ impl<'a> Default for &'a mut ByteStr { } } -#[unstable(feature = "bstr", issue = "134915")] -impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { - #[inline] - fn from(s: &'a [u8; N]) -> Self { - ByteStr::from_bytes(s) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a [u8]> for &'a ByteStr { - #[inline] - fn from(s: &'a [u8]) -> Self { - ByteStr::from_bytes(s) - } -} +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteStr::from_bytes(s) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteStr::from_bytes(s) +// } +// } // Omitted due to slice-from-array-issue-113238: // @@ -280,13 +282,15 @@ impl<'a> From<&'a [u8]> for &'a ByteStr { // } // } -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a str> for &'a ByteStr { - #[inline] - fn from(s: &'a str) -> Self { - ByteStr::from_bytes(s.as_bytes()) - } -} +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for &'a ByteStr { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteStr::from_bytes(s.as_bytes()) +// } +// } #[unstable(feature = "bstr", issue = "134915")] impl hash::Hash for ByteStr { From 022e7c0bb90e1f7e3e485f16c5c3df616113940f Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Wed, 22 Jan 2025 09:19:24 +0200 Subject: [PATCH 7/8] Add doc aliases for BStr and BString --- library/alloc/src/bstr.rs | 1 + library/core/src/bstr.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index acb60d9ca8618..61e61019b508c 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -46,6 +46,7 @@ use crate::vec::Vec; #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[derive(Clone)] +#[doc(alias = "BString")] pub struct ByteString(pub Vec<u8>); impl ByteString { diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs index 9f20eb1a0e8ee..74e07f3d242cd 100644 --- a/library/core/src/bstr.rs +++ b/library/core/src/bstr.rs @@ -39,6 +39,7 @@ use crate::{fmt, hash}; /// #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] +#[doc(alias = "BStr")] pub struct ByteStr(pub [u8]); impl ByteStr { From 865471f99b315f603ed2085344381b46dbc6e55a Mon Sep 17 00:00:00 2001 From: Josh Triplett <josh@joshtriplett.org> Date: Wed, 22 Jan 2025 17:53:39 +0200 Subject: [PATCH 8/8] Implement `CloneToUninit` for `ByteStr` --- library/core/src/clone.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index ec1aed53eaf72..00300328b64c1 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr { } } +#[unstable(feature = "bstr", issue = "134915")] +unsafe impl CloneToUninit for crate::bstr::ByteStr { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]` + unsafe { self.as_bytes().clone_to_uninit(dst) } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust