2020-04-26 20:11:16 +01:00
|
|
|
//! A UTF-8 encoded read-only string using Bytes as storage.
|
|
|
|
|
2020-12-12 23:24:00 +00:00
|
|
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
|
|
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
|
|
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
|
|
|
|
2019-12-07 09:59:39 +06:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::{borrow, fmt, hash, ops, str};
|
|
|
|
|
|
|
|
use bytes::Bytes;
|
|
|
|
|
2020-04-26 20:11:16 +01:00
|
|
|
/// A UTF-8 encoded string with [`Bytes`] as a storage.
|
2019-12-07 09:59:39 +06:00
|
|
|
///
|
2019-12-22 16:24:28 +04:00
|
|
|
/// [`Bytes`]: https://docs.rs/bytes/0.5.3/bytes/struct.Bytes.html
|
2020-01-14 15:06:02 -08:00
|
|
|
#[derive(Clone, Eq, Ord, PartialOrd, Default)]
|
2019-12-07 09:59:39 +06:00
|
|
|
pub struct ByteString(Bytes);
|
|
|
|
|
|
|
|
impl ByteString {
|
|
|
|
/// Creates a new `ByteString`.
|
2019-12-22 16:24:28 +04:00
|
|
|
pub fn new() -> Self {
|
|
|
|
ByteString(Bytes::new())
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2019-12-22 16:24:28 +04:00
|
|
|
pub const fn from_static(src: &'static str) -> ByteString {
|
|
|
|
Self(Bytes::from_static(src.as_bytes()))
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|
2019-12-07 10:48:22 +06:00
|
|
|
|
|
|
|
/// Creates a new `ByteString` from a Bytes.
|
2020-07-22 12:32:13 +09:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// This function is unsafe because it does not check the bytes passed to it
|
|
|
|
/// are valid UTF-8. If this constraint is violated,
|
|
|
|
/// it may cause memory unsafety issues with future users of the `ByteString`,
|
|
|
|
/// as we assume that `ByteString`s are valid UTF-8.
|
|
|
|
/// However, the most likely issue is that the data gets corrupted.
|
2019-12-22 16:24:28 +04:00
|
|
|
pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
|
2019-12-07 10:48:22 +06:00
|
|
|
Self(src)
|
|
|
|
}
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq<str> for ByteString {
|
|
|
|
fn eq(&self, other: &str) -> bool {
|
|
|
|
&self[..] == other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-13 11:58:31 +06:00
|
|
|
impl<T: AsRef<str>> PartialEq<T> for ByteString {
|
|
|
|
fn eq(&self, other: &T) -> bool {
|
|
|
|
&self[..] == other.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<[u8]> for ByteString {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
self.0.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 15:06:02 -08:00
|
|
|
impl AsRef<str> for ByteString {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
&*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 09:59:39 +06:00
|
|
|
impl hash::Hash for ByteString {
|
|
|
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
2019-12-07 11:51:47 +06:00
|
|
|
(**self).hash(state);
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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<str> for ByteString {
|
|
|
|
fn borrow(&self) -> &str {
|
|
|
|
&*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<String> 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<Self, Self::Error> {
|
|
|
|
let _ = str::from_utf8(value)?;
|
|
|
|
Ok(ByteString(Bytes::copy_from_slice(value)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<Vec<u8>> for ByteString {
|
|
|
|
type Error = str::Utf8Error;
|
|
|
|
|
|
|
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
|
|
|
let _ = str::from_utf8(value.as_ref())?;
|
|
|
|
Ok(ByteString(Bytes::from(value)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 10:22:08 +06:00
|
|
|
impl TryFrom<Bytes> for ByteString {
|
|
|
|
type Error = str::Utf8Error;
|
|
|
|
|
|
|
|
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
|
|
|
|
let _ = str::from_utf8(value.as_ref())?;
|
|
|
|
Ok(ByteString(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<bytes::BytesMut> for ByteString {
|
|
|
|
type Error = str::Utf8Error;
|
|
|
|
|
|
|
|
fn try_from(value: bytes::BytesMut) -> Result<Self, Self::Error> {
|
|
|
|
let _ = str::from_utf8(value.as_ref())?;
|
|
|
|
Ok(ByteString(value.freeze()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 09:59:39 +06:00
|
|
|
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<Self, Self::Error> {
|
|
|
|
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 {
|
2020-12-12 23:24:00 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-12-07 09:59:39 +06:00
|
|
|
(**self).fmt(fmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ByteString {
|
2020-12-12 23:24:00 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-12-07 09:59:39 +06:00
|
|
|
(**self).fmt(fmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-30 11:54:40 +06:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
mod serde {
|
|
|
|
use serde::de::{Deserialize, Deserializer};
|
|
|
|
use serde::ser::{Serialize, Serializer};
|
|
|
|
|
|
|
|
use super::ByteString;
|
|
|
|
|
|
|
|
impl Serialize for ByteString {
|
|
|
|
#[inline]
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
serializer.serialize_str(self.as_ref())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for ByteString {
|
|
|
|
#[inline]
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
String::deserialize(deserializer).map(ByteString::from)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 09:59:39 +06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
2019-12-07 11:51:47 +06:00
|
|
|
use std::collections::hash_map::DefaultHasher;
|
|
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
|
2020-01-13 11:58:31 +06:00
|
|
|
#[test]
|
|
|
|
fn test_partial_eq() {
|
|
|
|
let s: ByteString = ByteString::from_static("test");
|
|
|
|
assert_eq!(s, "test");
|
|
|
|
assert_eq!(s, *"test");
|
|
|
|
assert_eq!(s, "test".to_string());
|
|
|
|
}
|
|
|
|
|
2019-12-22 16:24:28 +04:00
|
|
|
#[test]
|
|
|
|
fn test_new() {
|
|
|
|
let _: ByteString = ByteString::new();
|
|
|
|
}
|
|
|
|
|
2019-12-07 11:51:47 +06:00
|
|
|
#[test]
|
|
|
|
fn test_hash() {
|
|
|
|
let mut hasher1 = DefaultHasher::default();
|
|
|
|
"str".hash(&mut hasher1);
|
|
|
|
|
|
|
|
let mut hasher2 = DefaultHasher::default();
|
|
|
|
let s = ByteString::from_static("str");
|
|
|
|
s.hash(&mut hasher2);
|
|
|
|
assert_eq!(hasher1.finish(), hasher2.finish());
|
|
|
|
}
|
2019-12-07 09:59:39 +06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_string() {
|
|
|
|
let s: ByteString = "hello".to_string().into();
|
|
|
|
assert_eq!(&s, "hello");
|
2020-01-14 15:06:02 -08:00
|
|
|
let t: &str = s.as_ref();
|
|
|
|
assert_eq!(t, "hello");
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_str() {
|
|
|
|
let _: ByteString = "str".into();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_static_str() {
|
2020-01-28 20:27:33 +09:00
|
|
|
static _S: ByteString = ByteString::from_static("hello");
|
2019-12-07 09:59:39 +06:00
|
|
|
let _ = ByteString::from_static("str");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-12-07 10:22:08 +06:00
|
|
|
fn test_try_from_rbytes() {
|
2019-12-07 09:59:39 +06:00
|
|
|
let _ = ByteString::try_from(b"nice bytes").unwrap();
|
|
|
|
}
|
2019-12-07 10:22:08 +06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_from_bytes() {
|
|
|
|
let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_from_bytesmut() {
|
|
|
|
let _ = ByteString::try_from(bytes::BytesMut::from(&b"nice bytes"[..])).unwrap();
|
|
|
|
}
|
2020-03-30 11:54:40 +06:00
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
#[test]
|
|
|
|
fn test_serialize() {
|
|
|
|
let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap();
|
|
|
|
assert_eq!(s, "nice bytes");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize() {
|
|
|
|
let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
|
|
|
|
assert_eq!(s, r#""nice bytes""#);
|
|
|
|
}
|
2019-12-07 09:59:39 +06:00
|
|
|
}
|