bytes_str/
byte_str.rs

1use std::{
2    borrow::{Borrow, Cow},
3    cmp::Ordering,
4    ffi::OsStr,
5    fmt::{self, Debug, Display},
6    hash::{Hash, Hasher},
7    ops::{Deref, Index},
8    path::Path,
9    slice::SliceIndex,
10    str::Utf8Error,
11};
12
13use bytes::Bytes;
14
15use crate::BytesString;
16
17/// [str], but backed by [Bytes].
18#[derive(Clone, Default, PartialEq, Eq)]
19pub struct BytesStr {
20    pub(crate) bytes: Bytes,
21}
22
23impl BytesStr {
24    /// Creates a new empty BytesStr.
25    ///
26    /// # Examples
27    ///
28    /// ```
29    /// use bytes_str::BytesStr;
30    ///
31    /// let s = BytesStr::new();
32    ///
33    /// assert_eq!(s.as_str(), "");
34    /// ```
35    pub fn new() -> Self {
36        Self {
37            bytes: Bytes::new(),
38        }
39    }
40
41    /// Creates a new BytesStr from a static string.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use bytes_str::BytesStr;
47    pub fn from_static(bytes: &'static str) -> Self {
48        Self {
49            bytes: Bytes::from_static(bytes.as_bytes()),
50        }
51    }
52
53    /// Creates a new BytesStr from a [Bytes].
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use bytes_str::BytesStr;
59    /// use bytes::Bytes;
60    ///
61    /// let s = BytesStr::from_utf8(Bytes::from_static(b"hello")).unwrap();
62    ///
63    /// assert_eq!(s.as_str(), "hello");
64    /// ```
65    pub fn from_utf8(bytes: Bytes) -> Result<Self, Utf8Error> {
66        std::str::from_utf8(&bytes)?;
67
68        Ok(Self { bytes })
69    }
70
71    /// Creates a new BytesStr from a [Bytes].
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// use bytes_str::BytesStr;
77    /// use bytes::Bytes;
78    ///     
79    /// let s = BytesStr::from_utf8_slice(b"hello").unwrap();
80    ///
81    /// assert_eq!(s.as_str(), "hello");
82    /// ```
83    pub fn from_utf8_slice(bytes: &[u8]) -> Result<Self, Utf8Error> {
84        std::str::from_utf8(bytes)?;
85
86        Ok(Self {
87            bytes: Bytes::copy_from_slice(bytes),
88        })
89    }
90
91    /// Creates a new BytesStr from a static UTF-8 slice.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use bytes_str::BytesStr;
97    ///     
98    /// let s = BytesStr::from_static_utf8_slice(b"hello").unwrap();
99    ///
100    /// assert_eq!(s.as_str(), "hello");
101    /// ```
102    pub fn from_static_utf8_slice(bytes: &'static [u8]) -> Result<Self, Utf8Error> {
103        std::str::from_utf8(bytes)?;
104
105        Ok(Self {
106            bytes: Bytes::from_static(bytes),
107        })
108    }
109
110    /// Returns a string slice containing the entire BytesStr.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use bytes_str::BytesStr;
116    ///
117    /// let s = BytesStr::from_static("hello");
118    ///
119    /// assert_eq!(s.as_str(), "hello");
120    /// ```
121    pub fn as_str(&self) -> &str {
122        unsafe { std::str::from_utf8_unchecked(&self.bytes) }
123    }
124}
125
126impl Deref for BytesStr {
127    type Target = str;
128
129    fn deref(&self) -> &Self::Target {
130        self.as_ref()
131    }
132}
133
134impl AsRef<str> for BytesStr {
135    fn as_ref(&self) -> &str {
136        self.as_str()
137    }
138}
139
140impl From<String> for BytesStr {
141    fn from(s: String) -> Self {
142        Self {
143            bytes: Bytes::from(s),
144        }
145    }
146}
147
148impl From<&'static str> for BytesStr {
149    fn from(s: &'static str) -> Self {
150        Self {
151            bytes: Bytes::from_static(s.as_bytes()),
152        }
153    }
154}
155
156impl From<BytesStr> for BytesString {
157    fn from(s: BytesStr) -> Self {
158        Self {
159            bytes: s.bytes.into(),
160        }
161    }
162}
163
164impl From<BytesString> for BytesStr {
165    fn from(s: BytesString) -> Self {
166        Self {
167            bytes: s.bytes.into(),
168        }
169    }
170}
171
172impl AsRef<[u8]> for BytesStr {
173    fn as_ref(&self) -> &[u8] {
174        self.bytes.as_ref()
175    }
176}
177
178impl AsRef<Bytes> for BytesStr {
179    fn as_ref(&self) -> &Bytes {
180        &self.bytes
181    }
182}
183
184impl AsRef<OsStr> for BytesStr {
185    fn as_ref(&self) -> &OsStr {
186        OsStr::new(self.as_str())
187    }
188}
189
190impl AsRef<Path> for BytesStr {
191    fn as_ref(&self) -> &Path {
192        Path::new(self.as_str())
193    }
194}
195
196impl Borrow<str> for BytesStr {
197    fn borrow(&self) -> &str {
198        self.as_str()
199    }
200}
201
202impl Debug for BytesStr {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        Debug::fmt(self.as_str(), f)
205    }
206}
207
208impl Display for BytesStr {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        Display::fmt(self.as_str(), f)
211    }
212}
213
214impl Extend<BytesStr> for BytesString {
215    fn extend<T: IntoIterator<Item = BytesStr>>(&mut self, iter: T) {
216        self.bytes.extend(iter.into_iter().map(|s| s.bytes));
217    }
218}
219
220impl<I> Index<I> for BytesStr
221where
222    I: SliceIndex<str>,
223{
224    type Output = I::Output;
225
226    fn index(&self, index: I) -> &Self::Output {
227        self.as_str().index(index)
228    }
229}
230
231impl PartialEq<str> for BytesStr {
232    fn eq(&self, other: &str) -> bool {
233        self.as_str() == other
234    }
235}
236
237impl PartialEq<&'_ str> for BytesStr {
238    fn eq(&self, other: &&str) -> bool {
239        self.as_str() == *other
240    }
241}
242
243impl PartialEq<Cow<'_, str>> for BytesStr {
244    fn eq(&self, other: &Cow<'_, str>) -> bool {
245        self.as_str() == *other
246    }
247}
248
249impl PartialEq<BytesStr> for str {
250    fn eq(&self, other: &BytesStr) -> bool {
251        self == other.as_str()
252    }
253}
254
255impl PartialEq<BytesStr> for &'_ str {
256    fn eq(&self, other: &BytesStr) -> bool {
257        *self == other.as_str()
258    }
259}
260
261impl PartialEq<BytesStr> for Bytes {
262    fn eq(&self, other: &BytesStr) -> bool {
263        self == other.as_bytes()
264    }
265}
266
267impl PartialEq<String> for BytesStr {
268    fn eq(&self, other: &String) -> bool {
269        self.as_str() == other
270    }
271}
272
273impl PartialEq<BytesStr> for String {
274    fn eq(&self, other: &BytesStr) -> bool {
275        self == other.as_str()
276    }
277}
278
279impl Ord for BytesStr {
280    fn cmp(&self, other: &Self) -> Ordering {
281        self.as_str().cmp(other.as_str())
282    }
283}
284
285impl PartialOrd for BytesStr {
286    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
287        Some(self.cmp(other))
288    }
289}
290
291/// This produces the same hash as [str]
292impl Hash for BytesStr {
293    fn hash<H: Hasher>(&self, state: &mut H) {
294        self.as_str().hash(state);
295    }
296}
297
298impl TryFrom<&'static [u8]> for BytesStr {
299    type Error = Utf8Error;
300
301    fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> {
302        Self::from_static_utf8_slice(value)
303    }
304}