use bytes::{Bytes, BytesMut};
#[derive(Clone)]
pub struct ByteStr {
bytes: Bytes,
}
impl ByteStr {
#[inline]
pub const fn new() -> ByteStr {
Self { bytes: Bytes::new() }
}
#[inline]
pub fn from_utf8(bytes: Bytes) -> Result<Self, std::str::Utf8Error> {
str::from_utf8(&bytes)?;
Ok(Self { bytes })
}
#[inline]
pub fn from_slice_of(subset: &str, bytes: &Bytes) -> Self {
Self { bytes: bytes.slice_ref(subset.as_bytes()) }
}
#[inline]
pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> Self {
Self { bytes }
}
#[inline]
pub fn copy_from_str(string: &str) -> Self {
Self { bytes: Bytes::copy_from_slice(string.as_bytes()) }
}
#[inline]
pub const fn from_static(string: &'static str) -> Self {
Self { bytes: Bytes::from_static(string.as_bytes()) }
}
pub fn try_mut<F: FnOnce(&mut str)>(&mut self, f: F) -> bool {
match Bytes::try_into_mut(std::mem::take(&mut self.bytes)) {
Ok(mut original) => {
let str_mut = unsafe { str::from_utf8_unchecked_mut(&mut original) };
f(str_mut);
self.bytes = original.freeze();
true
},
Err(original) => {
self.bytes = original;
false
},
}
}
#[inline]
pub fn clear(&mut self) {
self.bytes.clear();
}
#[inline]
pub fn is_unique(&self) -> bool {
self.bytes.is_unique()
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.bytes) }
}
#[inline]
pub fn slice_ref(&self, subset: &str) -> Self {
Self { bytes: Bytes::slice_ref(&self.bytes, subset.as_bytes()) }
}
#[inline]
pub fn into_string(self) -> String {
unsafe { String::from_utf8_unchecked(Vec::from(self.bytes)) }
}
#[inline]
pub fn into_bytes(self) -> Bytes {
self.bytes
}
}
impl From<&'static str> for ByteStr {
#[inline]
fn from(value: &'static str) -> Self {
Self::from_static(value)
}
}
impl From<std::borrow::Cow<'static,str>> for ByteStr {
#[inline]
fn from(value: std::borrow::Cow<'static,str>) -> Self {
match value {
std::borrow::Cow::Borrowed(s) => Self::from(s),
std::borrow::Cow::Owned(s) => Self::from(s),
}
}
}
impl From<Box<str>> for ByteStr {
#[inline]
fn from(value: Box<str>) -> Self {
Self { bytes: Bytes::from(value.into_boxed_bytes()) }
}
}
impl From<String> for ByteStr {
#[inline]
fn from(value: String) -> Self {
Self { bytes: Bytes::from(value.into_bytes()) }
}
}
impl Default for ByteStr {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl From<ByteStr> for Bytes {
#[inline]
fn from(value: ByteStr) -> Self {
value.bytes
}
}
impl From<ByteStr> for BytesMut {
#[inline]
fn from(value: ByteStr) -> Self {
value.bytes.into()
}
}
impl From<ByteStr> for String {
#[inline]
fn from(value: ByteStr) -> Self {
value.into_string()
}
}
impl AsRef<[u8]> for ByteStr {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl AsRef<str> for ByteStr {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl std::ops::Deref for ByteStr {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl std::fmt::Display for ByteStr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.as_str(), f)
}
}
impl std::fmt::Debug for ByteStr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self.as_str(), f)
}
}
impl PartialEq for ByteStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
str::eq(self.as_str(), other.as_str())
}
}
impl PartialEq<str> for ByteStr {
#[inline]
fn eq(&self, other: &str) -> bool {
str::eq(self, other)
}
}
impl PartialEq<&str> for ByteStr {
#[inline]
fn eq(&self, other: &&str) -> bool {
str::eq(self, *other)
}
}
impl PartialEq<String> for ByteStr {
#[inline]
fn eq(&self, other: &String) -> bool {
str::eq(self, other)
}
}