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