mco_redis/bytes/
string.rs

1//! A UTF-8 encoded read-only string using Bytes as storage.
2use std::{borrow, convert::TryFrom, fmt, hash, ops, slice, str};
3
4use crate::bytes::{Bytes, BytesMut, BytesVec};
5
6/// An immutable UTF-8 encoded string with [`Bytes`] as a storage.
7#[derive(Clone, Default, Eq, PartialOrd, Ord)]
8pub struct ByteString(Bytes);
9
10impl ByteString {
11    /// Creates a new empty `ByteString`.
12    #[inline]
13    pub const fn new() -> Self {
14        ByteString(Bytes::new())
15    }
16
17    /// Get a reference to the underlying bytes.
18    #[inline]
19    pub fn as_slice(&self) -> &[u8] {
20        self.0.as_ref()
21    }
22
23    /// Get a reference to the underlying `Bytes` object.
24    #[inline]
25    pub fn as_bytes(&self) -> &Bytes {
26        &self.0
27    }
28
29    /// Unwraps this `ByteString` into the underlying `Bytes` object.
30    #[inline]
31    pub fn into_bytes(self) -> Bytes {
32        self.0
33    }
34
35    /// Creates a new `ByteString` from a `&'static str`.
36    #[inline]
37    pub const fn from_static(src: &'static str) -> ByteString {
38        Self(Bytes::from_static(src.as_bytes()))
39    }
40
41    /// Returns a slice of self for the provided range.
42    ///
43    /// This will increment the reference count for the underlying memory and
44    /// return a new `ByteString` handle set to the slice.
45    ///
46    /// This operation is `O(1)`.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use mco_redis::bytes::ByteString;
52    ///
53    /// let a = ByteString::from("hello world");
54    /// let b = a.slice(2..5);
55    ///
56    /// assert_eq!(b, "llo");
57    /// ```
58    ///
59    /// # Panics
60    ///
61    /// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing
62    /// will panic.
63    pub fn slice(
64        &self,
65        range: impl ops::RangeBounds<usize> + slice::SliceIndex<str> + Clone,
66    ) -> ByteString {
67        ops::Index::index(self.as_ref(), range.clone());
68        ByteString(self.0.slice(range))
69    }
70
71    /// Splits the bytestring into two at the given index.
72    ///
73    /// Afterwards `self` contains elements `[0, at)`, and the returned `ByteString`
74    /// contains elements `[at, len)`.
75    ///
76    /// This is an `O(1)` operation that just increases the reference count and
77    /// sets a few indices.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use mco_redis::bytes::ByteString;
83    ///
84    /// let mut a = ByteString::from("hello world");
85    /// let b = a.split_off(5);
86    ///
87    /// assert_eq!(a, "hello");
88    /// assert_eq!(b, " world");
89    /// ```
90    ///
91    /// # Panics
92    ///
93    /// Panics if `at > len`.
94    pub fn split_off(&mut self, at: usize) -> ByteString {
95        // check str
96        let _ = self.split_at(at);
97
98        ByteString(self.0.split_off(at))
99    }
100
101    /// Splits the bytestring into two at the given index.
102    ///
103    /// Afterwards `self` contains elements `[at, len)`, and the returned
104    /// `Bytes` contains elements `[0, at)`.
105    ///
106    /// This is an `O(1)` operation that just increases the reference count and
107    /// sets a few indices.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use mco_redis::bytes::ByteString;
113    ///
114    /// let mut a = ByteString::from("hello world");
115    /// let b = a.split_to(5);
116    ///
117    /// assert_eq!(a, " world");
118    /// assert_eq!(b, "hello");
119    /// ```
120    ///
121    /// # Panics
122    ///
123    /// Panics if `at > len`.
124    pub fn split_to(&mut self, at: usize) -> ByteString {
125        // check str
126        let _ = self.split_at(at);
127
128        ByteString(self.0.split_to(at))
129    }
130
131    /// Shortens the buffer to `len` bytes and dropping the rest.
132    #[inline]
133    pub fn trimdown(&mut self) {
134        self.0.trimdown()
135    }
136
137    /// Creates a new `ByteString` from a Bytes.
138    ///
139    /// # Safety
140    /// This function is unsafe because it does not check the bytes passed to it are valid UTF-8.
141    /// If this constraint is violated, it may cause memory unsafety issues with future users of
142    /// the `ByteString`, as we assume that `ByteString`s are valid UTF-8. However, the most likely
143    /// issue is that the data gets corrupted.
144    #[inline]
145    pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
146        Self(src)
147    }
148}
149
150impl PartialEq<str> for ByteString {
151    fn eq(&self, other: &str) -> bool {
152        &self[..] == other
153    }
154}
155
156impl<T: AsRef<str>> PartialEq<T> for ByteString {
157    fn eq(&self, other: &T) -> bool {
158        &self[..] == other.as_ref()
159    }
160}
161
162impl AsRef<str> for ByteString {
163    #[inline]
164    fn as_ref(&self) -> &str {
165        &*self
166    }
167}
168
169impl hash::Hash for ByteString {
170    fn hash<H: hash::Hasher>(&self, state: &mut H) {
171        (**self).hash(state);
172    }
173}
174
175impl ops::Deref for ByteString {
176    type Target = str;
177
178    #[inline]
179    fn deref(&self) -> &str {
180        let bytes = self.0.as_ref();
181        // SAFETY:
182        // UTF-8 validity is guaranteed during construction.
183        unsafe { str::from_utf8_unchecked(bytes) }
184    }
185}
186
187impl borrow::Borrow<str> for ByteString {
188    #[inline]
189    fn borrow(&self) -> &str {
190        &*self
191    }
192}
193
194impl From<String> for ByteString {
195    #[inline]
196    fn from(value: String) -> Self {
197        Self(Bytes::from(value))
198    }
199}
200
201impl From<&str> for ByteString {
202    #[inline]
203    fn from(value: &str) -> Self {
204        Self(Bytes::copy_from_slice(value.as_ref()))
205    }
206}
207
208impl<'a> From<borrow::Cow<'a, str>> for ByteString {
209    #[inline]
210    fn from(value: borrow::Cow<'a, str>) -> Self {
211        match value {
212            borrow::Cow::Owned(s) => Self::from(s),
213            borrow::Cow::Borrowed(s) => Self::from(s),
214        }
215    }
216}
217
218impl TryFrom<&[u8]> for ByteString {
219    type Error = ();
220
221    #[inline]
222    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
223        if utf8::is_valid(value) {
224            Ok(ByteString(Bytes::copy_from_slice(value)))
225        } else {
226            Err(())
227        }
228    }
229}
230
231impl TryFrom<Vec<u8>> for ByteString {
232    type Error = ();
233
234    #[inline]
235    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
236        if utf8::is_valid(&value) {
237            Ok(ByteString(Bytes::from(value)))
238        } else {
239            Err(())
240        }
241    }
242}
243
244impl TryFrom<Bytes> for ByteString {
245    type Error = ();
246
247    #[inline]
248    fn try_from(value: Bytes) -> Result<Self, Self::Error> {
249        if utf8::is_valid(&value) {
250            Ok(ByteString(value))
251        } else {
252            Err(())
253        }
254    }
255}
256
257impl TryFrom<BytesMut> for ByteString {
258    type Error = ();
259
260    #[inline]
261    fn try_from(value: BytesMut) -> Result<Self, Self::Error> {
262        if utf8::is_valid(&value) {
263            Ok(ByteString(value.freeze()))
264        } else {
265            Err(())
266        }
267    }
268}
269
270impl TryFrom<BytesVec> for ByteString {
271    type Error = ();
272
273    #[inline]
274    fn try_from(value: BytesVec) -> Result<Self, Self::Error> {
275        if utf8::is_valid(&value) {
276            Ok(ByteString(value.freeze()))
277        } else {
278            Err(())
279        }
280    }
281}
282
283impl fmt::Debug for ByteString {
284    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
285        (**self).fmt(fmt)
286    }
287}
288
289impl fmt::Display for ByteString {
290    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
291        (**self).fmt(fmt)
292    }
293}
294
295mod serde {
296    use serde::de::{Deserialize, Deserializer};
297    use serde::ser::{Serialize, Serializer};
298
299    use super::ByteString;
300
301    impl Serialize for ByteString {
302        #[inline]
303        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
304        where
305            S: Serializer,
306        {
307            serializer.serialize_str(self.as_ref())
308        }
309    }
310
311    impl<'de> Deserialize<'de> for ByteString {
312        #[inline]
313        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
314        where
315            D: Deserializer<'de>,
316        {
317            String::deserialize(deserializer).map(ByteString::from)
318        }
319    }
320}
321
322#[cfg(feature = "simd")]
323mod utf8 {
324    pub(super) fn is_valid(input: &[u8]) -> bool {
325        simdutf8::basic::from_utf8(input).is_ok()
326    }
327}
328
329#[cfg(not(feature = "simd"))]
330mod utf8 {
331    pub(super) fn is_valid(input: &[u8]) -> bool {
332        std::str::from_utf8(input).is_ok()
333    }
334}
335
336#[cfg(test)]
337mod test {
338    use std::borrow::ToOwned;
339    use std::collections::hash_map::DefaultHasher;
340    use std::hash::{Hash, Hasher};
341
342    use super::*;
343
344    #[test]
345    fn test_basics() {
346        let mut s = ByteString::from_static("test");
347        s.trimdown();
348        assert_eq!(s, "test");
349        assert_eq!(s, *"test");
350        assert_eq!(s, "test".to_owned());
351        assert_eq!(s.as_slice(), b"test");
352        assert_eq!(s.as_bytes(), &Bytes::copy_from_slice(b"test"));
353
354        assert_eq!(format!("{}", s), "test");
355        assert_eq!(format!("{:?}", s), "\"test\"");
356        assert_eq!(s.into_bytes(), Bytes::copy_from_slice(b"test"));
357    }
358
359    #[test]
360    fn test_split() {
361        let mut s = ByteString::from_static("helloworld");
362        let s1 = s.split_off(5);
363        assert_eq!(s, "hello");
364        assert_eq!(s1, "world");
365
366        let mut s = ByteString::from_static("helloworld");
367        let s1 = s.split_to(5);
368        assert_eq!(s, "world");
369        assert_eq!(s1, "hello");
370    }
371
372    #[test]
373    fn test_new() {
374        let _: ByteString = ByteString::new();
375    }
376
377    #[test]
378    fn test_hash() {
379        let mut hasher1 = DefaultHasher::default();
380        "str".hash(&mut hasher1);
381
382        let mut hasher2 = DefaultHasher::default();
383        let s = ByteString::from_static("str");
384        s.hash(&mut hasher2);
385        assert_eq!(hasher1.finish(), hasher2.finish());
386    }
387
388    #[test]
389    fn test_from_string() {
390        let s: ByteString = "hello".to_owned().into();
391        assert_eq!(&s, "hello");
392        let t: &str = s.as_ref();
393        assert_eq!(t, "hello");
394    }
395
396    #[test]
397    fn test_from_str() {
398        let _: ByteString = "str".into();
399    }
400
401    #[test]
402    fn test_from_static_str() {
403        static _S: ByteString = ByteString::from_static("hello");
404        let _ = ByteString::from_static("str");
405    }
406
407    #[test]
408    fn test_try_from() {
409        let _ = ByteString::try_from(&b"nice bytes"[..]).unwrap();
410        let _ = ByteString::try_from(b"nice bytes".to_vec()).unwrap();
411        let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
412        let _ = ByteString::try_from(BytesMut::from(&b"nice bytes"[..])).unwrap();
413        let _ =
414            ByteString::try_from(BytesVec::copy_from_slice(&b"nice bytes"[..])).unwrap();
415    }
416
417    #[test]
418    fn test_serialize() {
419        let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap();
420        assert_eq!(s, "nice bytes");
421    }
422
423    #[test]
424    fn test_deserialize() {
425        let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
426        assert_eq!(s, r#""nice bytes""#);
427    }
428}