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/// A reference-counted `str` backed by [Bytes].
18///
19/// Clone is cheap thanks to [Bytes].
20///
21///
22/// # Features
23///
24/// ## `rkyv`
25///
26/// If the `rkyv` feature is enabled, the [BytesStr] type will be
27/// [rkyv::Archive], [rkyv::Serialize], and [rkyv::Deserialize].
28///
29///
30/// ## `serde`
31///
32/// If the `serde` feature is enabled, the [BytesStr] type will be
33/// [serde::Serialize] and [serde::Deserialize].
34///
35/// The [BytesStr] type will be serialized as a [str] type.
36#[derive(Clone, Default, PartialEq, Eq)]
37#[cfg_attr(
38    feature = "rkyv",
39    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
40)]
41pub struct BytesStr {
42    pub(crate) bytes: Bytes,
43}
44
45impl BytesStr {
46    /// Creates a new empty BytesStr.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use bytes_str::BytesStr;
52    ///
53    /// let s = BytesStr::new();
54    ///
55    /// assert_eq!(s.as_str(), "");
56    /// ```
57    pub fn new() -> Self {
58        Self {
59            bytes: Bytes::new(),
60        }
61    }
62
63    /// Creates a new BytesStr from a static string.
64    ///
65    /// # Examples
66    ///
67    /// ```
68    /// use bytes_str::BytesStr;
69    ///
70    /// let s = BytesStr::from_static("hello");
71    /// assert_eq!(s.as_str(), "hello");
72    /// ```
73    pub fn from_static(bytes: &'static str) -> Self {
74        Self {
75            bytes: Bytes::from_static(bytes.as_bytes()),
76        }
77    }
78
79    /// Creates a new BytesStr from a [Bytes].
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use bytes_str::BytesStr;
85    /// use bytes::Bytes;
86    ///
87    /// let s = BytesStr::from_utf8(Bytes::from_static(b"hello")).unwrap();
88    ///
89    /// assert_eq!(s.as_str(), "hello");
90    /// ```
91    pub fn from_utf8(bytes: Bytes) -> Result<Self, Utf8Error> {
92        std::str::from_utf8(&bytes)?;
93
94        Ok(Self { bytes })
95    }
96
97    /// Creates a new BytesStr from a [Vec<u8>].
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use bytes_str::BytesStr;
103    /// use bytes::Bytes;
104    ///
105    /// let s = BytesStr::from_utf8_vec(b"hello".to_vec()).unwrap();
106    ///
107    /// assert_eq!(s.as_str(), "hello");
108    /// ```
109    pub fn from_utf8_vec(bytes: Vec<u8>) -> Result<Self, Utf8Error> {
110        std::str::from_utf8(&bytes)?;
111
112        Ok(Self {
113            bytes: Bytes::from(bytes),
114        })
115    }
116
117    /// Creates a new BytesStr from a [Bytes] without checking if the bytes
118    /// are valid UTF-8.
119    ///
120    /// # Safety
121    ///
122    /// This function is unsafe because it does not check if the bytes are valid
123    /// UTF-8. If the bytes are not valid UTF-8, the resulting BytesStr will
124    pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> Self {
125        Self { bytes }
126    }
127
128    /// Creates a new BytesStr from a [Vec<u8>] without checking if the bytes
129    /// are valid UTF-8.
130    ///
131    /// # Safety
132    ///
133    /// This function is unsafe because it does not check if the bytes are valid
134    /// UTF-8. If the bytes are not valid UTF-8, the resulting BytesStr will
135    /// be invalid.
136    pub unsafe fn from_utf8_vec_unchecked(bytes: Vec<u8>) -> Self {
137        Self::from_utf8_unchecked(Bytes::from(bytes))
138    }
139
140    /// Creates a new BytesStr from a [Bytes].
141    ///
142    /// # Examples
143    ///
144    /// ```
145    /// use bytes_str::BytesStr;
146    /// use bytes::Bytes;
147    ///     
148    /// let s = BytesStr::from_utf8_slice(b"hello").unwrap();
149    ///
150    /// assert_eq!(s.as_str(), "hello");
151    /// ```
152    pub fn from_utf8_slice(bytes: &[u8]) -> Result<Self, Utf8Error> {
153        std::str::from_utf8(bytes)?;
154
155        Ok(Self {
156            bytes: Bytes::copy_from_slice(bytes),
157        })
158    }
159
160    /// Creates a new BytesStr from a [Bytes] without checking if the bytes
161    /// are valid UTF-8.
162    ///
163    /// # Safety
164    ///
165    /// This function is unsafe because it does not check if the bytes are valid
166    /// UTF-8. If the bytes are not valid UTF-8, the resulting BytesStr will
167    /// be invalid.
168    pub unsafe fn from_utf8_slice_unchecked(bytes: &[u8]) -> Self {
169        Self {
170            bytes: Bytes::copy_from_slice(bytes),
171        }
172    }
173
174    /// Creates a new BytesStr from a static UTF-8 slice.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use bytes_str::BytesStr;
180    ///     
181    /// let s = BytesStr::from_static_utf8_slice(b"hello").unwrap();
182    ///
183    /// assert_eq!(s.as_str(), "hello");
184    /// ```
185    pub fn from_static_utf8_slice(bytes: &'static [u8]) -> Result<Self, Utf8Error> {
186        std::str::from_utf8(bytes)?;
187
188        Ok(Self {
189            bytes: Bytes::from_static(bytes),
190        })
191    }
192
193    /// Creates a new BytesStr from a static UTF-8 slice without checking if the
194    /// bytes are valid UTF-8.
195    ///
196    /// # Safety
197    ///
198    /// This function is unsafe because it does not check if the bytes are valid
199    /// UTF-8. If the bytes are not valid UTF-8, the resulting BytesStr will
200    /// be invalid.
201    pub unsafe fn from_static_utf8_slice_unchecked(bytes: &'static [u8]) -> Self {
202        Self {
203            bytes: Bytes::from_static(bytes),
204        }
205    }
206
207    /// Returns a string slice containing the entire BytesStr.
208    ///
209    /// # Examples
210    ///
211    /// ```
212    /// use bytes_str::BytesStr;
213    ///
214    /// let s = BytesStr::from_static("hello");
215    ///
216    /// assert_eq!(s.as_str(), "hello");
217    /// ```
218    pub fn as_str(&self) -> &str {
219        unsafe { std::str::from_utf8_unchecked(&self.bytes) }
220    }
221}
222
223impl Deref for BytesStr {
224    type Target = str;
225
226    fn deref(&self) -> &Self::Target {
227        self.as_ref()
228    }
229}
230
231impl AsRef<str> for BytesStr {
232    fn as_ref(&self) -> &str {
233        self.as_str()
234    }
235}
236
237impl From<String> for BytesStr {
238    fn from(s: String) -> Self {
239        Self {
240            bytes: Bytes::from(s),
241        }
242    }
243}
244
245impl From<&'static str> for BytesStr {
246    fn from(s: &'static str) -> Self {
247        Self {
248            bytes: Bytes::from_static(s.as_bytes()),
249        }
250    }
251}
252
253impl From<BytesStr> for BytesString {
254    fn from(s: BytesStr) -> Self {
255        Self {
256            bytes: s.bytes.into(),
257        }
258    }
259}
260
261impl From<BytesString> for BytesStr {
262    fn from(s: BytesString) -> Self {
263        Self {
264            bytes: s.bytes.into(),
265        }
266    }
267}
268
269impl AsRef<[u8]> for BytesStr {
270    fn as_ref(&self) -> &[u8] {
271        self.bytes.as_ref()
272    }
273}
274
275impl AsRef<Bytes> for BytesStr {
276    fn as_ref(&self) -> &Bytes {
277        &self.bytes
278    }
279}
280
281impl AsRef<OsStr> for BytesStr {
282    fn as_ref(&self) -> &OsStr {
283        OsStr::new(self.as_str())
284    }
285}
286
287impl AsRef<Path> for BytesStr {
288    fn as_ref(&self) -> &Path {
289        Path::new(self.as_str())
290    }
291}
292
293impl Borrow<str> for BytesStr {
294    fn borrow(&self) -> &str {
295        self.as_str()
296    }
297}
298
299impl Debug for BytesStr {
300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301        Debug::fmt(self.as_str(), f)
302    }
303}
304
305impl Display for BytesStr {
306    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307        Display::fmt(self.as_str(), f)
308    }
309}
310
311impl Extend<BytesStr> for BytesString {
312    fn extend<T: IntoIterator<Item = BytesStr>>(&mut self, iter: T) {
313        self.bytes.extend(iter.into_iter().map(|s| s.bytes));
314    }
315}
316
317impl<I> Index<I> for BytesStr
318where
319    I: SliceIndex<str>,
320{
321    type Output = I::Output;
322
323    fn index(&self, index: I) -> &Self::Output {
324        self.as_str().index(index)
325    }
326}
327
328impl PartialEq<str> for BytesStr {
329    fn eq(&self, other: &str) -> bool {
330        self.as_str() == other
331    }
332}
333
334impl PartialEq<&'_ str> for BytesStr {
335    fn eq(&self, other: &&str) -> bool {
336        self.as_str() == *other
337    }
338}
339
340impl PartialEq<Cow<'_, str>> for BytesStr {
341    fn eq(&self, other: &Cow<'_, str>) -> bool {
342        self.as_str() == *other
343    }
344}
345
346impl PartialEq<BytesStr> for str {
347    fn eq(&self, other: &BytesStr) -> bool {
348        self == other.as_str()
349    }
350}
351
352impl PartialEq<BytesStr> for &'_ str {
353    fn eq(&self, other: &BytesStr) -> bool {
354        *self == other.as_str()
355    }
356}
357
358impl PartialEq<BytesStr> for Bytes {
359    fn eq(&self, other: &BytesStr) -> bool {
360        *self == other.bytes
361    }
362}
363
364impl PartialEq<String> for BytesStr {
365    fn eq(&self, other: &String) -> bool {
366        self.as_str() == other
367    }
368}
369
370impl PartialEq<BytesStr> for String {
371    fn eq(&self, other: &BytesStr) -> bool {
372        self == other.as_str()
373    }
374}
375
376impl Ord for BytesStr {
377    fn cmp(&self, other: &Self) -> Ordering {
378        self.as_str().cmp(other.as_str())
379    }
380}
381
382impl PartialOrd for BytesStr {
383    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
384        Some(self.cmp(other))
385    }
386}
387
388/// This produces the same hash as [str]
389impl Hash for BytesStr {
390    fn hash<H: Hasher>(&self, state: &mut H) {
391        self.as_str().hash(state);
392    }
393}
394
395impl TryFrom<&'static [u8]> for BytesStr {
396    type Error = Utf8Error;
397
398    fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> {
399        Self::from_static_utf8_slice(value)
400    }
401}
402
403#[cfg(feature = "serde")]
404mod serde_impl {
405    use serde::{Deserialize, Deserializer, Serialize, Serializer};
406
407    use super::*;
408
409    impl<'de> Deserialize<'de> for BytesStr {
410        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
411        where
412            D: Deserializer<'de>,
413        {
414            let s = String::deserialize(deserializer)?;
415            Ok(Self::from(s))
416        }
417    }
418
419    impl Serialize for BytesStr {
420        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
421        where
422            S: Serializer,
423        {
424            serializer.serialize_str(self.as_str())
425        }
426    }
427}
428
429#[cfg(test)]
430mod tests {
431    use std::{
432        borrow::{Borrow, Cow},
433        collections::{hash_map::DefaultHasher, HashMap},
434        ffi::OsStr,
435        hash::{Hash, Hasher},
436        path::Path,
437    };
438
439    use bytes::Bytes;
440
441    use super::*;
442    use crate::BytesString;
443
444    #[test]
445    fn test_new() {
446        let s = BytesStr::new();
447        assert_eq!(s.as_str(), "");
448        assert_eq!(s.len(), 0);
449        assert!(s.is_empty());
450    }
451
452    #[test]
453    fn test_default() {
454        let s: BytesStr = Default::default();
455        assert_eq!(s.as_str(), "");
456        assert_eq!(s.len(), 0);
457        assert!(s.is_empty());
458    }
459
460    #[test]
461    fn test_from_static() {
462        let s = BytesStr::from_static("hello world");
463        assert_eq!(s.as_str(), "hello world");
464        assert_eq!(s.len(), 11);
465        assert!(!s.is_empty());
466
467        // Test with unicode
468        let s = BytesStr::from_static("한국어 🌍");
469        assert_eq!(s.as_str(), "한국어 🌍");
470    }
471
472    #[test]
473    fn test_from_utf8() {
474        let bytes = Bytes::from_static(b"hello");
475        let s = BytesStr::from_utf8(bytes).unwrap();
476        assert_eq!(s.as_str(), "hello");
477
478        // Test with unicode
479        let bytes = Bytes::from("한국어".as_bytes());
480        let s = BytesStr::from_utf8(bytes).unwrap();
481        assert_eq!(s.as_str(), "한국어");
482
483        // Test with invalid UTF-8
484        let invalid_bytes = Bytes::from_static(&[0xff, 0xfe]);
485        assert!(BytesStr::from_utf8(invalid_bytes).is_err());
486    }
487
488    #[test]
489    fn test_from_utf8_vec() {
490        let vec = b"hello world".to_vec();
491        let s = BytesStr::from_utf8_vec(vec).unwrap();
492        assert_eq!(s.as_str(), "hello world");
493
494        // Test with unicode
495        let vec = "한국어 🎉".as_bytes().to_vec();
496        let s = BytesStr::from_utf8_vec(vec).unwrap();
497        assert_eq!(s.as_str(), "한국어 🎉");
498
499        // Test with invalid UTF-8
500        let invalid_vec = vec![0xff, 0xfe];
501        assert!(BytesStr::from_utf8_vec(invalid_vec).is_err());
502    }
503
504    #[test]
505    fn test_from_utf8_unchecked() {
506        let bytes = Bytes::from_static(b"hello");
507        let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
508        assert_eq!(s.as_str(), "hello");
509
510        // Test with unicode
511        let bytes = Bytes::from("한국어".as_bytes());
512        let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
513        assert_eq!(s.as_str(), "한국어");
514    }
515
516    #[test]
517    fn test_from_utf8_vec_unchecked() {
518        let vec = b"hello world".to_vec();
519        let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
520        assert_eq!(s.as_str(), "hello world");
521
522        // Test with unicode
523        let vec = "한국어 🎉".as_bytes().to_vec();
524        let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
525        assert_eq!(s.as_str(), "한국어 🎉");
526    }
527
528    #[test]
529    fn test_from_utf8_slice() {
530        let s = BytesStr::from_utf8_slice(b"hello").unwrap();
531        assert_eq!(s.as_str(), "hello");
532
533        // Test with unicode
534        let s = BytesStr::from_utf8_slice("한국어".as_bytes()).unwrap();
535        assert_eq!(s.as_str(), "한국어");
536
537        // Test with invalid UTF-8
538        assert!(BytesStr::from_utf8_slice(&[0xff, 0xfe]).is_err());
539    }
540
541    #[test]
542    fn test_from_utf8_slice_unchecked() {
543        let s = unsafe { BytesStr::from_utf8_slice_unchecked(b"hello") };
544        assert_eq!(s.as_str(), "hello");
545
546        // Test with unicode
547        let s = unsafe { BytesStr::from_utf8_slice_unchecked("한국어".as_bytes()) };
548        assert_eq!(s.as_str(), "한국어");
549    }
550
551    #[test]
552    fn test_from_static_utf8_slice() {
553        let s = BytesStr::from_static_utf8_slice(b"hello").unwrap();
554        assert_eq!(s.as_str(), "hello");
555
556        // Test with unicode
557        let s = BytesStr::from_static_utf8_slice("한국어".as_bytes()).unwrap();
558        assert_eq!(s.as_str(), "한국어");
559
560        // Test with invalid UTF-8
561        assert!(BytesStr::from_static_utf8_slice(&[0xff, 0xfe]).is_err());
562    }
563
564    #[test]
565    fn test_from_static_utf8_slice_unchecked() {
566        let s = unsafe { BytesStr::from_static_utf8_slice_unchecked(b"hello") };
567        assert_eq!(s.as_str(), "hello");
568
569        // Test with unicode
570        let s = unsafe { BytesStr::from_static_utf8_slice_unchecked("한국어".as_bytes()) };
571        assert_eq!(s.as_str(), "한국어");
572    }
573
574    #[test]
575    fn test_as_str() {
576        let s = BytesStr::from_static("hello world");
577        assert_eq!(s.as_str(), "hello world");
578
579        // Test with unicode
580        let s = BytesStr::from_static("한국어 🌍");
581        assert_eq!(s.as_str(), "한국어 🌍");
582    }
583
584    #[test]
585    fn test_deref() {
586        let s = BytesStr::from_static("hello world");
587
588        // Test that we can call str methods directly
589        assert_eq!(s.len(), 11);
590        assert!(s.contains("world"));
591        assert!(s.starts_with("hello"));
592        assert!(s.ends_with("world"));
593        assert_eq!(&s[0..5], "hello");
594    }
595
596    #[test]
597    fn test_as_ref_str() {
598        let s = BytesStr::from_static("hello");
599        let str_ref: &str = s.as_ref();
600        assert_eq!(str_ref, "hello");
601    }
602
603    #[test]
604    fn test_as_ref_bytes() {
605        let s = BytesStr::from_static("hello");
606        let bytes_ref: &[u8] = s.as_ref();
607        assert_eq!(bytes_ref, b"hello");
608    }
609
610    #[test]
611    fn test_as_ref_bytes_type() {
612        let s = BytesStr::from_static("hello");
613        let bytes_ref: &Bytes = s.as_ref();
614        assert_eq!(bytes_ref.as_ref(), b"hello");
615    }
616
617    #[test]
618    fn test_as_ref_os_str() {
619        let s = BytesStr::from_static("hello/world");
620        let os_str_ref: &OsStr = s.as_ref();
621        assert_eq!(os_str_ref, OsStr::new("hello/world"));
622    }
623
624    #[test]
625    fn test_as_ref_path() {
626        let s = BytesStr::from_static("hello/world");
627        let path_ref: &Path = s.as_ref();
628        assert_eq!(path_ref, Path::new("hello/world"));
629    }
630
631    #[test]
632    fn test_borrow() {
633        let s = BytesStr::from_static("hello");
634        let borrowed: &str = s.borrow();
635        assert_eq!(borrowed, "hello");
636    }
637
638    #[test]
639    fn test_from_string() {
640        let original = String::from("hello world");
641        let s = BytesStr::from(original);
642        assert_eq!(s.as_str(), "hello world");
643    }
644
645    #[test]
646    fn test_from_static_str() {
647        let s = BytesStr::from("hello world");
648        assert_eq!(s.as_str(), "hello world");
649    }
650
651    #[test]
652    fn test_conversion_to_bytes_string() {
653        let s = BytesStr::from_static("hello");
654        let bytes_string: BytesString = s.into();
655        assert_eq!(bytes_string.as_str(), "hello");
656    }
657
658    #[test]
659    fn test_conversion_from_bytes_string() {
660        let mut bytes_string = BytesString::from("hello");
661        bytes_string.push_str(" world");
662        let s: BytesStr = bytes_string.into();
663        assert_eq!(s.as_str(), "hello world");
664    }
665
666    #[test]
667    fn test_try_from_static_slice() {
668        let s = BytesStr::try_from(b"hello" as &'static [u8]).unwrap();
669        assert_eq!(s.as_str(), "hello");
670
671        // Test with invalid UTF-8
672        let invalid_slice: &'static [u8] = &[0xff, 0xfe];
673        assert!(BytesStr::try_from(invalid_slice).is_err());
674    }
675
676    #[test]
677    fn test_debug() {
678        let s = BytesStr::from_static("hello");
679        assert_eq!(format!("{:?}", s), "\"hello\"");
680
681        let s = BytesStr::from_static("hello\nworld");
682        assert_eq!(format!("{:?}", s), "\"hello\\nworld\"");
683    }
684
685    #[test]
686    fn test_display() {
687        let s = BytesStr::from_static("hello world");
688        assert_eq!(format!("{}", s), "hello world");
689
690        let s = BytesStr::from_static("한국어 🌍");
691        assert_eq!(format!("{}", s), "한국어 🌍");
692    }
693
694    #[test]
695    fn test_index() {
696        let s = BytesStr::from_static("hello world");
697        assert_eq!(&s[0..5], "hello");
698        assert_eq!(&s[6..], "world");
699        assert_eq!(&s[..5], "hello");
700        assert_eq!(&s[6..11], "world");
701
702        // Test with unicode
703        let s = BytesStr::from_static("한국어");
704        assert_eq!(&s[0..6], "한국");
705    }
706
707    #[test]
708    fn test_partial_eq_str() {
709        let s = BytesStr::from_static("hello");
710
711        // Test BytesStr == str
712        assert_eq!(s, "hello");
713        assert_ne!(s, "world");
714
715        // Test str == BytesStr
716        assert_eq!("hello", s);
717        assert_ne!("world", s);
718
719        // Test BytesStr == &str
720        let hello_str = "hello";
721        let world_str = "world";
722        assert_eq!(s, hello_str);
723        assert_ne!(s, world_str);
724
725        // Test &str == BytesStr
726        assert_eq!(hello_str, s);
727        assert_ne!(world_str, s);
728    }
729
730    #[test]
731    fn test_partial_eq_string() {
732        let s = BytesStr::from_static("hello");
733        let string = String::from("hello");
734        let other_string = String::from("world");
735
736        // Test BytesStr == String
737        assert_eq!(s, string);
738        assert_ne!(s, other_string);
739
740        // Test String == BytesStr
741        assert_eq!(string, s);
742        assert_ne!(other_string, s);
743    }
744
745    #[test]
746    fn test_partial_eq_cow() {
747        let s = BytesStr::from_static("hello");
748
749        assert_eq!(s, Cow::Borrowed("hello"));
750        assert_eq!(s, Cow::Owned(String::from("hello")));
751        assert_ne!(s, Cow::Borrowed("world"));
752        assert_ne!(s, Cow::Owned(String::from("world")));
753    }
754
755    #[test]
756    fn test_partial_eq_bytes() {
757        let s = BytesStr::from_static("hello");
758        let bytes = Bytes::from_static(b"hello");
759        let other_bytes = Bytes::from_static(b"world");
760
761        assert_eq!(bytes, s);
762        assert_ne!(other_bytes, s);
763    }
764
765    #[test]
766    fn test_partial_eq_bytes_str() {
767        let s1 = BytesStr::from_static("hello");
768        let s2 = BytesStr::from_static("hello");
769        let s3 = BytesStr::from_static("world");
770
771        assert_eq!(s1, s2);
772        assert_ne!(s1, s3);
773    }
774
775    #[test]
776    fn test_ordering() {
777        let s1 = BytesStr::from_static("apple");
778        let s2 = BytesStr::from_static("banana");
779        let s3 = BytesStr::from_static("apple");
780
781        assert!(s1 < s2);
782        assert!(s2 > s1);
783        assert_eq!(s1, s3);
784        assert!(s1 <= s3);
785        assert!(s1 >= s3);
786
787        // Test partial_cmp
788        assert_eq!(s1.partial_cmp(&s2), Some(std::cmp::Ordering::Less));
789        assert_eq!(s2.partial_cmp(&s1), Some(std::cmp::Ordering::Greater));
790        assert_eq!(s1.partial_cmp(&s3), Some(std::cmp::Ordering::Equal));
791    }
792
793    #[test]
794    fn test_hash() {
795        let s1 = BytesStr::from_static("hello");
796        let s2 = BytesStr::from_static("hello");
797        let s3 = BytesStr::from_static("world");
798
799        let mut hasher1 = DefaultHasher::new();
800        let mut hasher2 = DefaultHasher::new();
801        let mut hasher3 = DefaultHasher::new();
802
803        s1.hash(&mut hasher1);
804        s2.hash(&mut hasher2);
805        s3.hash(&mut hasher3);
806
807        assert_eq!(hasher1.finish(), hasher2.finish());
808        assert_ne!(hasher1.finish(), hasher3.finish());
809
810        // Test hash consistency with str
811        let mut str_hasher = DefaultHasher::new();
812        "hello".hash(&mut str_hasher);
813        assert_eq!(hasher1.finish(), str_hasher.finish());
814    }
815
816    #[test]
817    fn test_clone() {
818        let s1 = BytesStr::from_static("hello world");
819        let s2 = s1.clone();
820
821        assert_eq!(s1, s2);
822        assert_eq!(s1.as_str(), s2.as_str());
823
824        // Clone should be cheap (reference counting)
825        // Both should point to the same underlying data
826    }
827
828    #[test]
829    fn test_extend_bytes_string() {
830        let mut bytes_string = BytesString::from("hello");
831        let parts = vec![
832            BytesStr::from_static(" "),
833            BytesStr::from_static("world"),
834            BytesStr::from_static("!"),
835        ];
836
837        bytes_string.extend(parts);
838        assert_eq!(bytes_string.as_str(), "hello world!");
839    }
840
841    #[test]
842    fn test_unicode_handling() {
843        let s = BytesStr::from_static("Hello 🌍 한국어 🎉");
844        assert_eq!(s.as_str(), "Hello 🌍 한국어 🎉");
845        assert!(s.len() > 13); // More than ASCII length due to UTF-8 encoding
846
847        // Test indexing with unicode (be careful with boundaries)
848        let korean = BytesStr::from_static("한국어");
849        assert_eq!(korean.len(), 9); // 3 characters * 3 bytes each
850        assert_eq!(&korean[0..6], "한국"); // First two characters
851    }
852
853    #[test]
854    fn test_empty_strings() {
855        let s = BytesStr::new();
856        assert!(s.is_empty());
857        assert_eq!(s.len(), 0);
858        assert_eq!(s.as_str(), "");
859
860        let s = BytesStr::from_static("");
861        assert!(s.is_empty());
862        assert_eq!(s.len(), 0);
863        assert_eq!(s.as_str(), "");
864    }
865
866    #[test]
867    fn test_large_strings() {
868        let large_str = "a".repeat(10000);
869        let s = BytesStr::from(large_str.clone());
870        assert_eq!(s.len(), 10000);
871        assert_eq!(s.as_str(), large_str);
872    }
873
874    #[test]
875    fn test_hash_map_usage() {
876        let mut map = HashMap::new();
877        let key = BytesStr::from_static("key");
878        map.insert(key, "value");
879
880        let lookup_key = BytesStr::from_static("key");
881        assert_eq!(map.get(&lookup_key), Some(&"value"));
882
883        // Test that string can be used to lookup BytesStr key
884        assert_eq!(map.get("key"), Some(&"value"));
885    }
886
887    #[test]
888    fn test_memory_efficiency() {
889        // Test that cloning is cheap (reference counting)
890        let original = BytesStr::from(String::from("hello world"));
891        let clone1 = original.clone();
892        let clone2 = original.clone();
893
894        // All should have the same content
895        assert_eq!(original.as_str(), "hello world");
896        assert_eq!(clone1.as_str(), "hello world");
897        assert_eq!(clone2.as_str(), "hello world");
898
899        // They should be equal
900        assert_eq!(original, clone1);
901        assert_eq!(clone1, clone2);
902    }
903
904    #[test]
905    fn test_static_vs_owned() {
906        // Test static string
907        let static_str = BytesStr::from_static("hello");
908        assert_eq!(static_str.as_str(), "hello");
909
910        // Test owned string
911        let owned_str = BytesStr::from(String::from("hello"));
912        assert_eq!(owned_str.as_str(), "hello");
913
914        // They should be equal even if one is static and one is owned
915        assert_eq!(static_str, owned_str);
916    }
917
918    #[test]
919    fn test_error_cases() {
920        // Test various invalid UTF-8 sequences
921        let invalid_sequences = vec![
922            vec![0xff],             // Invalid start byte
923            vec![0xfe, 0xff],       // Invalid sequence
924            vec![0xc0, 0x80],       // Overlong encoding
925            vec![0xe0, 0x80, 0x80], // Overlong encoding
926        ];
927
928        for invalid in invalid_sequences {
929            assert!(BytesStr::from_utf8(Bytes::from(invalid.clone())).is_err());
930            assert!(BytesStr::from_utf8_vec(invalid.clone()).is_err());
931            assert!(BytesStr::from_utf8_slice(&invalid).is_err());
932        }
933    }
934
935    #[test]
936    fn test_boundary_conditions() {
937        // Test with single character
938        let s = BytesStr::from_static("a");
939        assert_eq!(s.len(), 1);
940        assert_eq!(s.as_str(), "a");
941
942        // Test with single unicode character
943        let s = BytesStr::from_static("한");
944        assert_eq!(s.len(), 3); // UTF-8 encoding
945        assert_eq!(s.as_str(), "한");
946
947        // Test with emoji
948        let s = BytesStr::from_static("🌍");
949        assert_eq!(s.len(), 4); // UTF-8 encoding
950        assert_eq!(s.as_str(), "🌍");
951    }
952}