1use std::convert::TryFrom;
3use std::{borrow, fmt, hash, ops, str};
4
5use bytes::Bytes;
6
7#[derive(Clone, Eq, Ord, PartialOrd, Default)]
11pub struct ByteString(Bytes);
12
13impl ByteString {
14 pub fn new() -> Self {
16 ByteString(Bytes::new())
17 }
18
19 pub fn get_ref(&self) -> &Bytes {
21 &self.0
22 }
23
24 pub fn into_inner(self) -> Bytes {
26 self.0
27 }
28
29 pub const fn from_static(src: &'static str) -> ByteString {
31 Self(Bytes::from_static(src.as_bytes()))
32 }
33
34 pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
36 Self(src)
37 }
38}
39
40impl PartialEq<str> for ByteString {
41 fn eq(&self, other: &str) -> bool {
42 &self[..] == other
43 }
44}
45
46impl<T: AsRef<str>> PartialEq<T> for ByteString {
47 fn eq(&self, other: &T) -> bool {
48 &self[..] == other.as_ref()
49 }
50}
51
52impl AsRef<[u8]> for ByteString {
53 fn as_ref(&self) -> &[u8] {
54 self.0.as_ref()
55 }
56}
57
58impl AsRef<str> for ByteString {
59 fn as_ref(&self) -> &str {
60 &*self
61 }
62}
63
64impl hash::Hash for ByteString {
65 fn hash<H: hash::Hasher>(&self, state: &mut H) {
66 (**self).hash(state);
67 }
68}
69
70impl ops::Deref for ByteString {
71 type Target = str;
72
73 #[inline]
74 fn deref(&self) -> &str {
75 let b = self.0.as_ref();
76 unsafe { str::from_utf8_unchecked(b) }
77 }
78}
79
80impl borrow::Borrow<str> for ByteString {
81 fn borrow(&self) -> &str {
82 &*self
83 }
84}
85
86impl From<String> for ByteString {
87 fn from(value: String) -> Self {
88 Self(Bytes::from(value))
89 }
90}
91
92impl<'a> From<&'a str> for ByteString {
93 fn from(value: &'a str) -> Self {
94 Self(Bytes::copy_from_slice(value.as_ref()))
95 }
96}
97
98impl<'a> TryFrom<&'a [u8]> for ByteString {
99 type Error = str::Utf8Error;
100
101 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
102 let _ = str::from_utf8(value)?;
103 Ok(ByteString(Bytes::copy_from_slice(value)))
104 }
105}
106
107impl TryFrom<Vec<u8>> for ByteString {
108 type Error = str::Utf8Error;
109
110 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
111 let _ = str::from_utf8(value.as_ref())?;
112 Ok(ByteString(Bytes::from(value)))
113 }
114}
115
116impl TryFrom<Bytes> for ByteString {
117 type Error = str::Utf8Error;
118
119 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
120 let _ = str::from_utf8(value.as_ref())?;
121 Ok(ByteString(value))
122 }
123}
124
125impl TryFrom<bytes::BytesMut> for ByteString {
126 type Error = str::Utf8Error;
127
128 fn try_from(value: bytes::BytesMut) -> Result<Self, Self::Error> {
129 let _ = str::from_utf8(value.as_ref())?;
130 Ok(ByteString(value.freeze()))
131 }
132}
133
134macro_rules! array_impls {
135 ($($len:expr)+) => {
136 $(
137 impl<'a> TryFrom<&'a [u8; $len]> for ByteString {
138 type Error = str::Utf8Error;
139
140 fn try_from(value: &'a [u8; $len]) -> Result<Self, Self::Error> {
141 ByteString::try_from(&value[..])
142 }
143 }
144 )+
145 }
146}
147
148array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
149
150impl fmt::Debug for ByteString {
151 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
152 (**self).fmt(fmt)
153 }
154}
155
156impl fmt::Display for ByteString {
157 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
158 (**self).fmt(fmt)
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165 use std::collections::hash_map::DefaultHasher;
166 use std::hash::{Hash, Hasher};
167
168 #[test]
169 fn test_partial_eq() {
170 let s: ByteString = ByteString::from_static("test");
171 assert_eq!(s, "test");
172 assert_eq!(s, *"test");
173 assert_eq!(s, "test".to_string());
174 }
175
176 #[test]
177 fn test_new() {
178 let _: ByteString = ByteString::new();
179 }
180
181 #[test]
182 fn test_hash() {
183 let mut hasher1 = DefaultHasher::default();
184 "str".hash(&mut hasher1);
185
186 let mut hasher2 = DefaultHasher::default();
187 let s = ByteString::from_static("str");
188 s.hash(&mut hasher2);
189 assert_eq!(hasher1.finish(), hasher2.finish());
190 }
191
192 #[test]
193 fn test_from_string() {
194 let s: ByteString = "hello".to_string().into();
195 assert_eq!(&s, "hello");
196 let t: &str = s.as_ref();
197 assert_eq!(t, "hello");
198 }
199
200 #[test]
201 fn test_from_str() {
202 let _: ByteString = "str".into();
203 }
204
205 #[test]
206 fn test_from_static_str() {
207 const _S: ByteString = ByteString::from_static("hello");
208 let _ = ByteString::from_static("str");
209 }
210
211 #[test]
212 fn test_try_from_rbytes() {
213 let _ = ByteString::try_from(b"nice bytes").unwrap();
214 }
215
216 #[test]
217 fn test_try_from_bytes() {
218 let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
219 }
220
221 #[test]
222 fn test_try_from_bytesmut() {
223 let _ = ByteString::try_from(bytes::BytesMut::from(&b"nice bytes"[..])).unwrap();
224 }
225}