From 6c00ab829662cd2f16cfe5e6dc7760ce9c77c058 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 7 Dec 2019 09:59:39 +0600 Subject: [PATCH] add string crate --- router/Cargo.toml | 3 +- router/src/lib.rs | 2 +- string/CHANGES.md | 5 ++ string/Cargo.toml | 19 ++++++ string/LICENSE-APACHE | 1 + string/LICENSE-MIT | 1 + string/src/lib.rs | 145 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 string/CHANGES.md create mode 100644 string/Cargo.toml create mode 120000 string/LICENSE-APACHE create mode 120000 string/LICENSE-MIT create mode 100644 string/src/lib.rs diff --git a/router/Cargo.toml b/router/Cargo.toml index cb8785f9..b3568701 100644 --- a/router/Cargo.toml +++ b/router/Cargo.toml @@ -22,8 +22,7 @@ default = ["http"] [dependencies] regex = "1.3.1" serde = "1.0.80" -# string = "0.2.1" -string = { git = "https://github.com/carllerche/string.git" } +bytestring = "0.1.0" log = "0.4.8" http = { version="0.2.0", optional=true } diff --git a/router/src/lib.rs b/router/src/lib.rs index 6c3928de..9c0e9b42 100644 --- a/router/src/lib.rs +++ b/router/src/lib.rs @@ -29,7 +29,7 @@ impl<'a> ResourcePath for &'a str { } } -impl> ResourcePath for string::String { +impl ResourcePath for bytesrting::ByteString { fn path(&self) -> &str { &*self } diff --git a/string/CHANGES.md b/string/CHANGES.md new file mode 100644 index 00000000..d01c5f7f --- /dev/null +++ b/string/CHANGES.md @@ -0,0 +1,5 @@ +# Changes + +[0.1.0] - 2019-12-07 + +* Initial release diff --git a/string/Cargo.toml b/string/Cargo.toml new file mode 100644 index 00000000..cf1fb8ca --- /dev/null +++ b/string/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "bytestring" +version = "0.1.0" +authors = ["Nikolay Kim "] +description = "A UTF-8 encoded string with Bytes as a storage" +keywords = ["actix"] +homepage = "https://actix.rs" +repository = "https://github.com/actix/actix-net.git" +documentation = "https://docs.rs/bytestring/" +license = "MIT/Apache-2.0" +edition = "2018" +workspace = ".." + +[lib] +name = "bytesrting" +path = "src/lib.rs" + +[dependencies] +bytes = "0.5.2" diff --git a/string/LICENSE-APACHE b/string/LICENSE-APACHE new file mode 120000 index 00000000..965b606f --- /dev/null +++ b/string/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/string/LICENSE-MIT b/string/LICENSE-MIT new file mode 120000 index 00000000..76219eb7 --- /dev/null +++ b/string/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/string/src/lib.rs b/string/src/lib.rs new file mode 100644 index 00000000..a8fab284 --- /dev/null +++ b/string/src/lib.rs @@ -0,0 +1,145 @@ +//! 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(); + } +}