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::{Buf, 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    /// Converts the [BytesStr] into a [Bytes].
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// use bytes_str::BytesStr;
228    /// use bytes::Bytes;
229    ///     
230    /// let s = BytesStr::from_static("hello");
231    /// let bytes = s.into_bytes();
232    ///
233    /// assert_eq!(bytes, Bytes::from_static(b"hello"));
234    /// ```
235    pub fn into_bytes(self) -> Bytes {
236        self.bytes
237    }
238
239    /// Advances the [BytesStr] by `n` bytes.
240    ///
241    /// # Panics
242    ///
243    /// Panics if `n` is greater than the length of the [BytesStr].
244    ///
245    /// Panics if `n` is not a character boundary.
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use bytes_str::BytesStr;
251    ///     
252    /// let mut s = BytesStr::from_static("hello");
253    /// s.advance(3);
254    ///
255    /// assert_eq!(s.as_str(), "llo");
256    /// ```
257    pub fn advance(&mut self, n: usize) {
258        if !self.is_char_boundary(n) {
259            panic!("n is not a character boundary");
260        }
261
262        self.bytes.advance(n);
263    }
264}
265
266impl Deref for BytesStr {
267    type Target = str;
268
269    fn deref(&self) -> &Self::Target {
270        self.as_ref()
271    }
272}
273
274impl AsRef<str> for BytesStr {
275    fn as_ref(&self) -> &str {
276        self.as_str()
277    }
278}
279
280impl From<String> for BytesStr {
281    fn from(s: String) -> Self {
282        Self {
283            bytes: Bytes::from(s),
284        }
285    }
286}
287
288impl From<&'static str> for BytesStr {
289    fn from(s: &'static str) -> Self {
290        Self {
291            bytes: Bytes::from_static(s.as_bytes()),
292        }
293    }
294}
295
296impl From<BytesStr> for BytesString {
297    fn from(s: BytesStr) -> Self {
298        Self {
299            bytes: s.bytes.into(),
300        }
301    }
302}
303
304impl From<BytesString> for BytesStr {
305    fn from(s: BytesString) -> Self {
306        Self {
307            bytes: s.bytes.into(),
308        }
309    }
310}
311
312impl AsRef<[u8]> for BytesStr {
313    fn as_ref(&self) -> &[u8] {
314        self.bytes.as_ref()
315    }
316}
317
318impl AsRef<Bytes> for BytesStr {
319    fn as_ref(&self) -> &Bytes {
320        &self.bytes
321    }
322}
323
324impl AsRef<OsStr> for BytesStr {
325    fn as_ref(&self) -> &OsStr {
326        OsStr::new(self.as_str())
327    }
328}
329
330impl AsRef<Path> for BytesStr {
331    fn as_ref(&self) -> &Path {
332        Path::new(self.as_str())
333    }
334}
335
336impl Borrow<str> for BytesStr {
337    fn borrow(&self) -> &str {
338        self.as_str()
339    }
340}
341
342impl Debug for BytesStr {
343    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344        Debug::fmt(self.as_str(), f)
345    }
346}
347
348impl Display for BytesStr {
349    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350        Display::fmt(self.as_str(), f)
351    }
352}
353
354impl Extend<BytesStr> for BytesString {
355    fn extend<T: IntoIterator<Item = BytesStr>>(&mut self, iter: T) {
356        self.bytes.extend(iter.into_iter().map(|s| s.bytes));
357    }
358}
359
360impl<I> Index<I> for BytesStr
361where
362    I: SliceIndex<str>,
363{
364    type Output = I::Output;
365
366    fn index(&self, index: I) -> &Self::Output {
367        self.as_str().index(index)
368    }
369}
370
371impl PartialEq<str> for BytesStr {
372    fn eq(&self, other: &str) -> bool {
373        self.as_str() == other
374    }
375}
376
377impl PartialEq<&'_ str> for BytesStr {
378    fn eq(&self, other: &&str) -> bool {
379        self.as_str() == *other
380    }
381}
382
383impl PartialEq<Cow<'_, str>> for BytesStr {
384    fn eq(&self, other: &Cow<'_, str>) -> bool {
385        self.as_str() == *other
386    }
387}
388
389impl PartialEq<BytesStr> for str {
390    fn eq(&self, other: &BytesStr) -> bool {
391        self == other.as_str()
392    }
393}
394
395impl PartialEq<BytesStr> for &'_ str {
396    fn eq(&self, other: &BytesStr) -> bool {
397        *self == other.as_str()
398    }
399}
400
401impl PartialEq<BytesStr> for Bytes {
402    fn eq(&self, other: &BytesStr) -> bool {
403        *self == other.bytes
404    }
405}
406
407impl PartialEq<String> for BytesStr {
408    fn eq(&self, other: &String) -> bool {
409        self.as_str() == other
410    }
411}
412
413impl PartialEq<BytesStr> for String {
414    fn eq(&self, other: &BytesStr) -> bool {
415        self == other.as_str()
416    }
417}
418
419impl Ord for BytesStr {
420    fn cmp(&self, other: &Self) -> Ordering {
421        self.as_str().cmp(other.as_str())
422    }
423}
424
425impl PartialOrd for BytesStr {
426    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
427        Some(self.cmp(other))
428    }
429}
430
431/// This produces the same hash as [str]
432impl Hash for BytesStr {
433    fn hash<H: Hasher>(&self, state: &mut H) {
434        self.as_str().hash(state);
435    }
436}
437
438impl TryFrom<&'static [u8]> for BytesStr {
439    type Error = Utf8Error;
440
441    fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> {
442        Self::from_static_utf8_slice(value)
443    }
444}
445
446#[cfg(feature = "serde")]
447mod serde_impl {
448    use serde::{Deserialize, Deserializer, Serialize, Serializer};
449
450    use super::*;
451
452    impl<'de> Deserialize<'de> for BytesStr {
453        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
454        where
455            D: Deserializer<'de>,
456        {
457            let s = String::deserialize(deserializer)?;
458            Ok(Self::from(s))
459        }
460    }
461
462    impl Serialize for BytesStr {
463        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
464        where
465            S: Serializer,
466        {
467            serializer.serialize_str(self.as_str())
468        }
469    }
470}
471
472#[cfg(test)]
473mod tests {
474    use std::{
475        borrow::{Borrow, Cow},
476        collections::{hash_map::DefaultHasher, HashMap},
477        ffi::OsStr,
478        hash::{Hash, Hasher},
479        path::Path,
480    };
481
482    use bytes::Bytes;
483
484    use super::*;
485    use crate::BytesString;
486
487    #[test]
488    fn test_new() {
489        let s = BytesStr::new();
490        assert_eq!(s.as_str(), "");
491        assert_eq!(s.len(), 0);
492        assert!(s.is_empty());
493    }
494
495    #[test]
496    fn test_default() {
497        let s: BytesStr = Default::default();
498        assert_eq!(s.as_str(), "");
499        assert_eq!(s.len(), 0);
500        assert!(s.is_empty());
501    }
502
503    #[test]
504    fn test_from_static() {
505        let s = BytesStr::from_static("hello world");
506        assert_eq!(s.as_str(), "hello world");
507        assert_eq!(s.len(), 11);
508        assert!(!s.is_empty());
509
510        // Test with unicode
511        let s = BytesStr::from_static("한국어 🌍");
512        assert_eq!(s.as_str(), "한국어 🌍");
513    }
514
515    #[test]
516    fn test_from_utf8() {
517        let bytes = Bytes::from_static(b"hello");
518        let s = BytesStr::from_utf8(bytes).unwrap();
519        assert_eq!(s.as_str(), "hello");
520
521        // Test with unicode
522        let bytes = Bytes::from("한국어".as_bytes());
523        let s = BytesStr::from_utf8(bytes).unwrap();
524        assert_eq!(s.as_str(), "한국어");
525
526        // Test with invalid UTF-8
527        let invalid_bytes = Bytes::from_static(&[0xff, 0xfe]);
528        assert!(BytesStr::from_utf8(invalid_bytes).is_err());
529    }
530
531    #[test]
532    fn test_from_utf8_vec() {
533        let vec = b"hello world".to_vec();
534        let s = BytesStr::from_utf8_vec(vec).unwrap();
535        assert_eq!(s.as_str(), "hello world");
536
537        // Test with unicode
538        let vec = "한국어 🎉".as_bytes().to_vec();
539        let s = BytesStr::from_utf8_vec(vec).unwrap();
540        assert_eq!(s.as_str(), "한국어 🎉");
541
542        // Test with invalid UTF-8
543        let invalid_vec = vec![0xff, 0xfe];
544        assert!(BytesStr::from_utf8_vec(invalid_vec).is_err());
545    }
546
547    #[test]
548    fn test_from_utf8_unchecked() {
549        let bytes = Bytes::from_static(b"hello");
550        let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
551        assert_eq!(s.as_str(), "hello");
552
553        // Test with unicode
554        let bytes = Bytes::from("한국어".as_bytes());
555        let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
556        assert_eq!(s.as_str(), "한국어");
557    }
558
559    #[test]
560    fn test_from_utf8_vec_unchecked() {
561        let vec = b"hello world".to_vec();
562        let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
563        assert_eq!(s.as_str(), "hello world");
564
565        // Test with unicode
566        let vec = "한국어 🎉".as_bytes().to_vec();
567        let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
568        assert_eq!(s.as_str(), "한국어 🎉");
569    }
570
571    #[test]
572    fn test_from_utf8_slice() {
573        let s = BytesStr::from_utf8_slice(b"hello").unwrap();
574        assert_eq!(s.as_str(), "hello");
575
576        // Test with unicode
577        let s = BytesStr::from_utf8_slice("한국어".as_bytes()).unwrap();
578        assert_eq!(s.as_str(), "한국어");
579
580        // Test with invalid UTF-8
581        assert!(BytesStr::from_utf8_slice(&[0xff, 0xfe]).is_err());
582    }
583
584    #[test]
585    fn test_from_utf8_slice_unchecked() {
586        let s = unsafe { BytesStr::from_utf8_slice_unchecked(b"hello") };
587        assert_eq!(s.as_str(), "hello");
588
589        // Test with unicode
590        let s = unsafe { BytesStr::from_utf8_slice_unchecked("한국어".as_bytes()) };
591        assert_eq!(s.as_str(), "한국어");
592    }
593
594    #[test]
595    fn test_from_static_utf8_slice() {
596        let s = BytesStr::from_static_utf8_slice(b"hello").unwrap();
597        assert_eq!(s.as_str(), "hello");
598
599        // Test with unicode
600        let s = BytesStr::from_static_utf8_slice("한국어".as_bytes()).unwrap();
601        assert_eq!(s.as_str(), "한국어");
602
603        // Test with invalid UTF-8
604        assert!(BytesStr::from_static_utf8_slice(&[0xff, 0xfe]).is_err());
605    }
606
607    #[test]
608    fn test_from_static_utf8_slice_unchecked() {
609        let s = unsafe { BytesStr::from_static_utf8_slice_unchecked(b"hello") };
610        assert_eq!(s.as_str(), "hello");
611
612        // Test with unicode
613        let s = unsafe { BytesStr::from_static_utf8_slice_unchecked("한국어".as_bytes()) };
614        assert_eq!(s.as_str(), "한국어");
615    }
616
617    #[test]
618    fn test_as_str() {
619        let s = BytesStr::from_static("hello world");
620        assert_eq!(s.as_str(), "hello world");
621
622        // Test with unicode
623        let s = BytesStr::from_static("한국어 🌍");
624        assert_eq!(s.as_str(), "한국어 🌍");
625    }
626
627    #[test]
628    fn test_deref() {
629        let s = BytesStr::from_static("hello world");
630
631        // Test that we can call str methods directly
632        assert_eq!(s.len(), 11);
633        assert!(s.contains("world"));
634        assert!(s.starts_with("hello"));
635        assert!(s.ends_with("world"));
636        assert_eq!(&s[0..5], "hello");
637    }
638
639    #[test]
640    fn test_as_ref_str() {
641        let s = BytesStr::from_static("hello");
642        let str_ref: &str = s.as_ref();
643        assert_eq!(str_ref, "hello");
644    }
645
646    #[test]
647    fn test_as_ref_bytes() {
648        let s = BytesStr::from_static("hello");
649        let bytes_ref: &[u8] = s.as_ref();
650        assert_eq!(bytes_ref, b"hello");
651    }
652
653    #[test]
654    fn test_as_ref_bytes_type() {
655        let s = BytesStr::from_static("hello");
656        let bytes_ref: &Bytes = s.as_ref();
657        assert_eq!(bytes_ref.as_ref(), b"hello");
658    }
659
660    #[test]
661    fn test_as_ref_os_str() {
662        let s = BytesStr::from_static("hello/world");
663        let os_str_ref: &OsStr = s.as_ref();
664        assert_eq!(os_str_ref, OsStr::new("hello/world"));
665    }
666
667    #[test]
668    fn test_as_ref_path() {
669        let s = BytesStr::from_static("hello/world");
670        let path_ref: &Path = s.as_ref();
671        assert_eq!(path_ref, Path::new("hello/world"));
672    }
673
674    #[test]
675    fn test_borrow() {
676        let s = BytesStr::from_static("hello");
677        let borrowed: &str = s.borrow();
678        assert_eq!(borrowed, "hello");
679    }
680
681    #[test]
682    fn test_from_string() {
683        let original = String::from("hello world");
684        let s = BytesStr::from(original);
685        assert_eq!(s.as_str(), "hello world");
686    }
687
688    #[test]
689    fn test_from_static_str() {
690        let s = BytesStr::from("hello world");
691        assert_eq!(s.as_str(), "hello world");
692    }
693
694    #[test]
695    fn test_conversion_to_bytes_string() {
696        let s = BytesStr::from_static("hello");
697        let bytes_string: BytesString = s.into();
698        assert_eq!(bytes_string.as_str(), "hello");
699    }
700
701    #[test]
702    fn test_conversion_from_bytes_string() {
703        let mut bytes_string = BytesString::from("hello");
704        bytes_string.push_str(" world");
705        let s: BytesStr = bytes_string.into();
706        assert_eq!(s.as_str(), "hello world");
707    }
708
709    #[test]
710    fn test_try_from_static_slice() {
711        let s = BytesStr::try_from(b"hello" as &'static [u8]).unwrap();
712        assert_eq!(s.as_str(), "hello");
713
714        // Test with invalid UTF-8
715        let invalid_slice: &'static [u8] = &[0xff, 0xfe];
716        assert!(BytesStr::try_from(invalid_slice).is_err());
717    }
718
719    #[test]
720    fn test_debug() {
721        let s = BytesStr::from_static("hello");
722        assert_eq!(format!("{:?}", s), "\"hello\"");
723
724        let s = BytesStr::from_static("hello\nworld");
725        assert_eq!(format!("{:?}", s), "\"hello\\nworld\"");
726    }
727
728    #[test]
729    fn test_display() {
730        let s = BytesStr::from_static("hello world");
731        assert_eq!(format!("{}", s), "hello world");
732
733        let s = BytesStr::from_static("한국어 🌍");
734        assert_eq!(format!("{}", s), "한국어 🌍");
735    }
736
737    #[test]
738    fn test_index() {
739        let s = BytesStr::from_static("hello world");
740        assert_eq!(&s[0..5], "hello");
741        assert_eq!(&s[6..], "world");
742        assert_eq!(&s[..5], "hello");
743        assert_eq!(&s[6..11], "world");
744
745        // Test with unicode
746        let s = BytesStr::from_static("한국어");
747        assert_eq!(&s[0..6], "한국");
748    }
749
750    #[test]
751    fn test_partial_eq_str() {
752        let s = BytesStr::from_static("hello");
753
754        // Test BytesStr == str
755        assert_eq!(s, "hello");
756        assert_ne!(s, "world");
757
758        // Test str == BytesStr
759        assert_eq!("hello", s);
760        assert_ne!("world", s);
761
762        // Test BytesStr == &str
763        let hello_str = "hello";
764        let world_str = "world";
765        assert_eq!(s, hello_str);
766        assert_ne!(s, world_str);
767
768        // Test &str == BytesStr
769        assert_eq!(hello_str, s);
770        assert_ne!(world_str, s);
771    }
772
773    #[test]
774    fn test_partial_eq_string() {
775        let s = BytesStr::from_static("hello");
776        let string = String::from("hello");
777        let other_string = String::from("world");
778
779        // Test BytesStr == String
780        assert_eq!(s, string);
781        assert_ne!(s, other_string);
782
783        // Test String == BytesStr
784        assert_eq!(string, s);
785        assert_ne!(other_string, s);
786    }
787
788    #[test]
789    fn test_partial_eq_cow() {
790        let s = BytesStr::from_static("hello");
791
792        assert_eq!(s, Cow::Borrowed("hello"));
793        assert_eq!(s, Cow::Owned(String::from("hello")));
794        assert_ne!(s, Cow::Borrowed("world"));
795        assert_ne!(s, Cow::Owned(String::from("world")));
796    }
797
798    #[test]
799    fn test_partial_eq_bytes() {
800        let s = BytesStr::from_static("hello");
801        let bytes = Bytes::from_static(b"hello");
802        let other_bytes = Bytes::from_static(b"world");
803
804        assert_eq!(bytes, s);
805        assert_ne!(other_bytes, s);
806    }
807
808    #[test]
809    fn test_partial_eq_bytes_str() {
810        let s1 = BytesStr::from_static("hello");
811        let s2 = BytesStr::from_static("hello");
812        let s3 = BytesStr::from_static("world");
813
814        assert_eq!(s1, s2);
815        assert_ne!(s1, s3);
816    }
817
818    #[test]
819    fn test_ordering() {
820        let s1 = BytesStr::from_static("apple");
821        let s2 = BytesStr::from_static("banana");
822        let s3 = BytesStr::from_static("apple");
823
824        assert!(s1 < s2);
825        assert!(s2 > s1);
826        assert_eq!(s1, s3);
827        assert!(s1 <= s3);
828        assert!(s1 >= s3);
829
830        // Test partial_cmp
831        assert_eq!(s1.partial_cmp(&s2), Some(std::cmp::Ordering::Less));
832        assert_eq!(s2.partial_cmp(&s1), Some(std::cmp::Ordering::Greater));
833        assert_eq!(s1.partial_cmp(&s3), Some(std::cmp::Ordering::Equal));
834    }
835
836    #[test]
837    fn test_hash() {
838        let s1 = BytesStr::from_static("hello");
839        let s2 = BytesStr::from_static("hello");
840        let s3 = BytesStr::from_static("world");
841
842        let mut hasher1 = DefaultHasher::new();
843        let mut hasher2 = DefaultHasher::new();
844        let mut hasher3 = DefaultHasher::new();
845
846        s1.hash(&mut hasher1);
847        s2.hash(&mut hasher2);
848        s3.hash(&mut hasher3);
849
850        assert_eq!(hasher1.finish(), hasher2.finish());
851        assert_ne!(hasher1.finish(), hasher3.finish());
852
853        // Test hash consistency with str
854        let mut str_hasher = DefaultHasher::new();
855        "hello".hash(&mut str_hasher);
856        assert_eq!(hasher1.finish(), str_hasher.finish());
857    }
858
859    #[test]
860    fn test_clone() {
861        let s1 = BytesStr::from_static("hello world");
862        let s2 = s1.clone();
863
864        assert_eq!(s1, s2);
865        assert_eq!(s1.as_str(), s2.as_str());
866
867        // Clone should be cheap (reference counting)
868        // Both should point to the same underlying data
869    }
870
871    #[test]
872    fn test_extend_bytes_string() {
873        let mut bytes_string = BytesString::from("hello");
874        let parts = vec![
875            BytesStr::from_static(" "),
876            BytesStr::from_static("world"),
877            BytesStr::from_static("!"),
878        ];
879
880        bytes_string.extend(parts);
881        assert_eq!(bytes_string.as_str(), "hello world!");
882    }
883
884    #[test]
885    fn test_unicode_handling() {
886        let s = BytesStr::from_static("Hello 🌍 한국어 🎉");
887        assert_eq!(s.as_str(), "Hello 🌍 한국어 🎉");
888        assert!(s.len() > 13); // More than ASCII length due to UTF-8 encoding
889
890        // Test indexing with unicode (be careful with boundaries)
891        let korean = BytesStr::from_static("한국어");
892        assert_eq!(korean.len(), 9); // 3 characters * 3 bytes each
893        assert_eq!(&korean[0..6], "한국"); // First two characters
894    }
895
896    #[test]
897    fn test_empty_strings() {
898        let s = BytesStr::new();
899        assert!(s.is_empty());
900        assert_eq!(s.len(), 0);
901        assert_eq!(s.as_str(), "");
902
903        let s = BytesStr::from_static("");
904        assert!(s.is_empty());
905        assert_eq!(s.len(), 0);
906        assert_eq!(s.as_str(), "");
907    }
908
909    #[test]
910    fn test_large_strings() {
911        let large_str = "a".repeat(10000);
912        let s = BytesStr::from(large_str.clone());
913        assert_eq!(s.len(), 10000);
914        assert_eq!(s.as_str(), large_str);
915    }
916
917    #[test]
918    fn test_hash_map_usage() {
919        let mut map = HashMap::new();
920        let key = BytesStr::from_static("key");
921        map.insert(key, "value");
922
923        let lookup_key = BytesStr::from_static("key");
924        assert_eq!(map.get(&lookup_key), Some(&"value"));
925
926        // Test that string can be used to lookup BytesStr key
927        assert_eq!(map.get("key"), Some(&"value"));
928    }
929
930    #[test]
931    fn test_memory_efficiency() {
932        // Test that cloning is cheap (reference counting)
933        let original = BytesStr::from(String::from("hello world"));
934        let clone1 = original.clone();
935        let clone2 = original.clone();
936
937        // All should have the same content
938        assert_eq!(original.as_str(), "hello world");
939        assert_eq!(clone1.as_str(), "hello world");
940        assert_eq!(clone2.as_str(), "hello world");
941
942        // They should be equal
943        assert_eq!(original, clone1);
944        assert_eq!(clone1, clone2);
945    }
946
947    #[test]
948    fn test_static_vs_owned() {
949        // Test static string
950        let static_str = BytesStr::from_static("hello");
951        assert_eq!(static_str.as_str(), "hello");
952
953        // Test owned string
954        let owned_str = BytesStr::from(String::from("hello"));
955        assert_eq!(owned_str.as_str(), "hello");
956
957        // They should be equal even if one is static and one is owned
958        assert_eq!(static_str, owned_str);
959    }
960
961    #[test]
962    fn test_error_cases() {
963        // Test various invalid UTF-8 sequences
964        let invalid_sequences = vec![
965            vec![0xff],             // Invalid start byte
966            vec![0xfe, 0xff],       // Invalid sequence
967            vec![0xc0, 0x80],       // Overlong encoding
968            vec![0xe0, 0x80, 0x80], // Overlong encoding
969        ];
970
971        for invalid in invalid_sequences {
972            assert!(BytesStr::from_utf8(Bytes::from(invalid.clone())).is_err());
973            assert!(BytesStr::from_utf8_vec(invalid.clone()).is_err());
974            assert!(BytesStr::from_utf8_slice(&invalid).is_err());
975        }
976    }
977
978    #[test]
979    fn test_boundary_conditions() {
980        // Test with single character
981        let s = BytesStr::from_static("a");
982        assert_eq!(s.len(), 1);
983        assert_eq!(s.as_str(), "a");
984
985        // Test with single unicode character
986        let s = BytesStr::from_static("한");
987        assert_eq!(s.len(), 3); // UTF-8 encoding
988        assert_eq!(s.as_str(), "한");
989
990        // Test with emoji
991        let s = BytesStr::from_static("🌍");
992        assert_eq!(s.len(), 4); // UTF-8 encoding
993        assert_eq!(s.as_str(), "🌍");
994    }
995}