From 6c00ab829662cd2f16cfe5e6dc7760ce9c77c058 Mon Sep 17 00:00:00 2001
From: Nikolay Kim <fafhrd91@gmail.com>
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<T: AsRef<[u8]>> ResourcePath for string::String<T> {
+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 <fafhrd91@gmail.com>"]
+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<str> for ByteString {
+    fn eq(&self, other: &str) -> bool {
+        &self[..] == other
+    }
+}
+
+impl hash::Hash for ByteString {
+    fn hash<H: hash::Hasher>(&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<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)))
+    }
+}
+
+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 {
+    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();
+    }
+}