//! A utl-8 encoded read-only string with Bytes as a storage. use std::convert::TryFrom; use std::{borrow, fmt, hash, ops, str}; use bytes::Bytes; /// A utf-8 encoded string with [`Bytes`] as a storage. /// /// [`Bytes`]: https://docs.rs/bytes/0.5.2/bytes/struct.Bytes.html #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default)] pub struct ByteString(Bytes); impl ByteString { /// Creates a new `ByteString`. pub fn new() -> String { String::default() } /// Get a reference to the underlying bytes object. pub fn get_ref(&self) -> &Bytes { &self.0 } /// Unwraps this `ByteString`, returning the underlying bytes object. pub fn into_inner(self) -> Bytes { self.0 } /// Creates a new `ByteString` from a static str. pub fn from_static(src: &'static str) -> ByteString { Self(Bytes::from_static(src.as_ref())) } } impl PartialEq for ByteString { fn eq(&self, other: &str) -> bool { &self[..] == other } } impl hash::Hash for ByteString { fn hash(&self, state: &mut H) { self.0.hash(state); } } impl ops::Deref for ByteString { type Target = str; #[inline] fn deref(&self) -> &str { let b = self.0.as_ref(); unsafe { str::from_utf8_unchecked(b) } } } impl borrow::Borrow for ByteString { fn borrow(&self) -> &str { &*self } } impl From for ByteString { fn from(value: String) -> Self { Self(Bytes::from(value)) } } impl<'a> From<&'a str> for ByteString { fn from(value: &'a str) -> Self { Self(Bytes::copy_from_slice(value.as_ref())) } } impl<'a> TryFrom<&'a [u8]> for ByteString { type Error = str::Utf8Error; fn try_from(value: &'a [u8]) -> Result { let _ = str::from_utf8(value)?; Ok(ByteString(Bytes::copy_from_slice(value))) } } impl TryFrom> for ByteString { type Error = str::Utf8Error; fn try_from(value: Vec) -> Result { let _ = str::from_utf8(value.as_ref())?; Ok(ByteString(Bytes::from(value))) } } macro_rules! array_impls { ($($len:expr)+) => { $( impl<'a> TryFrom<&'a [u8; $len]> for ByteString { type Error = str::Utf8Error; fn try_from(value: &'a [u8; $len]) -> Result { ByteString::try_from(&value[..]) } } )+ } } array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16); impl fmt::Debug for ByteString { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(fmt) } } impl fmt::Display for ByteString { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(fmt) } } #[cfg(test)] mod test { use super::*; #[test] fn test_from_string() { let s: ByteString = "hello".to_string().into(); assert_eq!(&s, "hello"); } #[test] fn test_from_str() { let _: ByteString = "str".into(); } #[test] fn test_from_static_str() { let _ = ByteString::from_static("str"); } #[test] fn test_try_from_bytes() { let _ = ByteString::try_from(b"nice bytes").unwrap(); } }