use crate::FromUtf8Error;
use super::Utf8BytesMut;
use core::iter::FromIterator;
use core::ops::{Deref, RangeBounds};
use core::{cmp, fmt, hash};
use std::borrow::Cow;
use alloc::{borrow::Borrow, boxed::Box, string::String, vec::Vec};
#[repr(transparent)]
pub struct Utf8Bytes {
#[deprecated = "use the accessors to preserve the invariants"]
inner: bytes::Bytes,
}
impl Utf8Bytes {
pub fn from_bytes(bytes: bytes::Bytes) -> Result<Self, FromUtf8Error<bytes::Bytes>> {
match str::from_utf8(&bytes) {
Ok(_) => Ok(unsafe { Self::from_bytes_unchecked(bytes) }),
Err(error) => Err(FromUtf8Error { bytes, error }),
}
}
pub const unsafe fn from_bytes_unchecked(bytes: bytes::Bytes) -> Self {
#[expect(deprecated)]
Self { inner: bytes }
}
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.inner()) }
}
}
impl Utf8Bytes {
#[inline]
pub const fn inner(&self) -> &bytes::Bytes {
#[expect(deprecated)]
&self.inner
}
#[inline]
pub const unsafe fn inner_mut(&mut self) -> &mut bytes::Bytes {
#[expect(deprecated)]
&mut self.inner
}
#[inline]
pub fn into_inner(self) -> bytes::Bytes {
#[expect(deprecated)]
self.inner
}
}
impl Utf8Bytes {
#[inline]
pub const fn new() -> Self {
unsafe { Self::from_bytes_unchecked(bytes::Bytes::new()) }
}
#[inline]
pub const fn from_static(str: &'static str) -> Self {
unsafe { Self::from_bytes_unchecked(bytes::Bytes::from_static(str.as_bytes())) }
}
pub fn from_owner<T>(owner: T) -> Self
where
T: AsRef<str> + Send + 'static,
{
#[repr(transparent)]
struct AsBytes<T>(T);
impl<T: AsRef<str>> AsRef<[u8]> for AsBytes<T> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref().as_bytes()
}
}
unsafe { Self::from_bytes_unchecked(bytes::Bytes::from_owner(AsBytes(owner))) }
}
#[inline]
pub const fn len(&self) -> usize {
self.inner().len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.inner().is_empty()
}
pub fn is_unique(&self) -> bool {
self.inner().is_unique()
}
pub fn copy_from_str(data: &str) -> Self {
unsafe { Self::from_bytes_unchecked(bytes::Bytes::copy_from_slice(data.as_bytes())) }
}
#[track_caller]
pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
let lo = range.start_bound().cloned();
let hi = range.end_bound().cloned();
self.as_str()
.get((lo, hi))
.expect("range out of bounds or not on a char boundary");
unsafe { Self::from_bytes_unchecked(self.inner().slice((lo, hi))) }
}
pub fn slice_ref(&self, subset: &str) -> Self {
unsafe { Self::from_bytes_unchecked(self.inner().slice_ref(subset.as_bytes())) }
}
#[must_use = "consider Bytes::truncate if you don't need the other half"]
pub fn split_off(&mut self, at: usize) -> Self {
let _char_boundary = self.as_str().split_at(at);
unsafe { Self::from_bytes_unchecked(self.inner_mut().split_off(at)) }
}
#[must_use = "consider Bytes::advance if you don't need the other half"]
pub fn split_to(&mut self, at: usize) -> Self {
let _char_boundary = self.as_str().split_at(at);
unsafe { Self::from_bytes_unchecked(self.inner_mut().split_to(at)) }
}
#[inline]
pub fn truncate(&mut self, len: usize) {
if len < self.len() {
let _char_boundary = self.as_str().split_at(len);
unsafe { self.inner_mut().truncate(len) }
};
}
#[inline]
pub fn clear(&mut self) {
self.truncate(0);
}
pub fn try_into_mut(self) -> Result<Utf8BytesMut, Utf8Bytes> {
match self.into_inner().try_into_mut() {
Ok(it) => Ok(unsafe { Utf8BytesMut::from_bytes_mut_unchecked(it) }),
Err(it) => Err(unsafe { Self::from_bytes_unchecked(it) }),
}
}
}
impl fmt::Debug for Utf8Bytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl fmt::Display for Utf8Bytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl Clone for Utf8Bytes {
#[inline]
fn clone(&self) -> Utf8Bytes {
unsafe { Self::from_bytes_unchecked(self.inner().clone()) }
}
fn clone_from(&mut self, source: &Self) {
self.inner().clone_from(&source.inner());
}
}
impl Deref for Utf8Bytes {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for Utf8Bytes {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<[u8]> for Utf8Bytes {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
impl hash::Hash for Utf8Bytes {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.as_str().hash(state);
}
}
impl Borrow<str> for Utf8Bytes {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl FromIterator<char> for Utf8Bytes {
fn from_iter<T: IntoIterator<Item = char>>(into_iter: T) -> Self {
String::from_iter(into_iter).into()
}
}
impl<T: AsRef<str>> PartialEq<T> for Utf8Bytes {
fn eq(&self, other: &T) -> bool {
self.as_str() == other.as_ref()
}
}
impl<T: AsRef<str>> PartialOrd<T> for Utf8Bytes {
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_ref())
}
}
impl Ord for Utf8Bytes {
fn cmp(&self, other: &Utf8Bytes) -> cmp::Ordering {
self.as_str().cmp(other.as_str())
}
}
impl Eq for Utf8Bytes {}
impl PartialEq<Utf8Bytes> for str {
fn eq(&self, other: &Utf8Bytes) -> bool {
self.eq(other.as_str())
}
}
impl PartialEq<Utf8Bytes> for String {
fn eq(&self, other: &Utf8Bytes) -> bool {
self.eq(other.as_str())
}
}
impl<'a> PartialEq<Utf8Bytes> for Cow<'a, str> {
fn eq(&self, other: &Utf8Bytes) -> bool {
self.eq(other.as_str())
}
}
impl PartialOrd<Utf8Bytes> for str {
fn partial_cmp(&self, other: &Utf8Bytes) -> Option<cmp::Ordering> {
self.partial_cmp(other.as_str())
}
}
impl PartialOrd<Utf8Bytes> for String {
fn partial_cmp(&self, other: &Utf8Bytes) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl PartialOrd<Utf8Bytes> for Cow<'_, str> {
fn partial_cmp(&self, other: &Utf8Bytes) -> Option<cmp::Ordering> {
(**self).partial_cmp(other.as_str())
}
}
impl Default for Utf8Bytes {
#[inline]
fn default() -> Utf8Bytes {
Utf8Bytes::new()
}
}
impl From<&'static str> for Utf8Bytes {
fn from(s: &'static str) -> Utf8Bytes {
Utf8Bytes::from_static(s)
}
}
impl From<Box<str>> for Utf8Bytes {
fn from(slice: Box<str>) -> Utf8Bytes {
unsafe { Self::from_bytes_unchecked(bytes::Bytes::from(slice.into_boxed_bytes())) }
}
}
impl From<Utf8Bytes> for bytes::Bytes {
fn from(utf8: Utf8Bytes) -> Self {
utf8.into_inner()
}
}
impl From<Utf8Bytes> for Utf8BytesMut {
fn from(bytes: Utf8Bytes) -> Self {
unsafe { Self::from_bytes_mut_unchecked(bytes.into_inner().into()) }
}
}
impl From<String> for Utf8Bytes {
fn from(s: String) -> Utf8Bytes {
unsafe { Utf8Bytes::from_bytes_unchecked(bytes::Bytes::from(s.into_bytes())) }
}
}
impl From<Utf8Bytes> for Vec<u8> {
fn from(utf8: Utf8Bytes) -> Vec<u8> {
utf8.into_inner().into()
}
}
impl From<Utf8Bytes> for String {
fn from(utf8: Utf8Bytes) -> Self {
unsafe { String::from_utf8_unchecked(utf8.into()) }
}
}