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, RangeBounds},
8 path::Path,
9 slice::SliceIndex,
10 str::Utf8Error,
11};
12
13use bytes::{Buf, Bytes};
14
15use crate::BytesString;
16
17#[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 pub fn new() -> Self {
58 Self {
59 bytes: Bytes::new(),
60 }
61 }
62
63 pub fn from_static(bytes: &'static str) -> Self {
74 Self {
75 bytes: Bytes::from_static(bytes.as_bytes()),
76 }
77 }
78
79 pub fn from_utf8(bytes: Bytes) -> Result<Self, Utf8Error> {
92 std::str::from_utf8(&bytes)?;
93
94 Ok(Self { bytes })
95 }
96
97 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 pub fn from_owned_utf8<T>(owner: T) -> Result<Self, Utf8Error>
121 where
122 T: AsRef<[u8]> + Send + 'static,
123 {
124 std::str::from_utf8(owner.as_ref())?;
125
126 Ok(Self {
127 bytes: Bytes::from_owner(owner),
128 })
129 }
130
131 pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> Self {
139 Self { bytes }
140 }
141
142 pub unsafe fn from_utf8_vec_unchecked(bytes: Vec<u8>) -> Self {
151 Self::from_utf8_unchecked(Bytes::from(bytes))
152 }
153
154 pub fn from_utf8_slice(bytes: &[u8]) -> Result<Self, Utf8Error> {
167 std::str::from_utf8(bytes)?;
168
169 Ok(Self {
170 bytes: Bytes::copy_from_slice(bytes),
171 })
172 }
173
174 pub unsafe fn from_utf8_slice_unchecked(bytes: &[u8]) -> Self {
183 Self {
184 bytes: Bytes::copy_from_slice(bytes),
185 }
186 }
187
188 pub fn from_str_slice(bytes: &str) -> Self {
200 Self {
201 bytes: Bytes::copy_from_slice(bytes.as_bytes()),
202 }
203 }
204
205 pub fn from_string(bytes: String) -> Self {
217 Self {
218 bytes: Bytes::from(bytes),
219 }
220 }
221
222 pub fn from_static_utf8_slice(bytes: &'static [u8]) -> Result<Self, Utf8Error> {
234 std::str::from_utf8(bytes)?;
235
236 Ok(Self {
237 bytes: Bytes::from_static(bytes),
238 })
239 }
240
241 pub unsafe fn from_static_utf8_slice_unchecked(bytes: &'static [u8]) -> Self {
250 Self {
251 bytes: Bytes::from_static(bytes),
252 }
253 }
254
255 pub fn as_str(&self) -> &str {
267 unsafe { std::str::from_utf8_unchecked(&self.bytes) }
268 }
269
270 pub fn into_bytes(self) -> Bytes {
284 self.bytes
285 }
286
287 pub const fn len(&self) -> usize {
299 self.bytes.len()
300 }
301
302 pub const fn is_empty(&self) -> bool {
314 self.bytes.is_empty()
315 }
316
317 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
334 let s = Self {
335 bytes: self.bytes.slice(range),
336 };
337
338 if !s.is_char_boundary(0) {
339 panic!("range start is not a character boundary");
340 }
341
342 if !s.is_char_boundary(s.len()) {
343 panic!("range end is not a character boundary");
344 }
345
346 s
347 }
348
349 pub fn slice_ref(&self, subset: &str) -> Self {
351 Self {
352 bytes: self.bytes.slice_ref(subset.as_bytes()),
353 }
354 }
355
356 pub fn advance(&mut self, n: usize) {
375 if !self.is_char_boundary(n) {
376 panic!("n is not a character boundary");
377 }
378
379 self.bytes.advance(n);
380 }
381}
382
383impl Deref for BytesStr {
384 type Target = str;
385
386 fn deref(&self) -> &Self::Target {
387 self.as_ref()
388 }
389}
390
391impl AsRef<str> for BytesStr {
392 fn as_ref(&self) -> &str {
393 self.as_str()
394 }
395}
396
397impl From<String> for BytesStr {
398 fn from(s: String) -> Self {
399 Self {
400 bytes: Bytes::from(s),
401 }
402 }
403}
404
405impl From<&'static str> for BytesStr {
406 fn from(s: &'static str) -> Self {
407 Self {
408 bytes: Bytes::from_static(s.as_bytes()),
409 }
410 }
411}
412
413impl From<BytesStr> for BytesString {
414 fn from(s: BytesStr) -> Self {
415 Self {
416 bytes: s.bytes.into(),
417 }
418 }
419}
420
421impl From<BytesString> for BytesStr {
422 fn from(s: BytesString) -> Self {
423 Self {
424 bytes: s.bytes.into(),
425 }
426 }
427}
428
429impl AsRef<[u8]> for BytesStr {
430 fn as_ref(&self) -> &[u8] {
431 self.bytes.as_ref()
432 }
433}
434
435impl AsRef<Bytes> for BytesStr {
436 fn as_ref(&self) -> &Bytes {
437 &self.bytes
438 }
439}
440
441impl AsRef<OsStr> for BytesStr {
442 fn as_ref(&self) -> &OsStr {
443 OsStr::new(self.as_str())
444 }
445}
446
447impl AsRef<Path> for BytesStr {
448 fn as_ref(&self) -> &Path {
449 Path::new(self.as_str())
450 }
451}
452
453impl Borrow<str> for BytesStr {
454 fn borrow(&self) -> &str {
455 self.as_str()
456 }
457}
458
459impl Debug for BytesStr {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 Debug::fmt(self.as_str(), f)
462 }
463}
464
465impl Display for BytesStr {
466 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467 Display::fmt(self.as_str(), f)
468 }
469}
470
471impl Extend<BytesStr> for BytesString {
472 fn extend<T: IntoIterator<Item = BytesStr>>(&mut self, iter: T) {
473 self.bytes.extend(iter.into_iter().map(|s| s.bytes));
474 }
475}
476
477impl<I> Index<I> for BytesStr
478where
479 I: SliceIndex<str>,
480{
481 type Output = I::Output;
482
483 fn index(&self, index: I) -> &Self::Output {
484 self.as_str().index(index)
485 }
486}
487
488impl PartialEq<str> for BytesStr {
489 fn eq(&self, other: &str) -> bool {
490 self.as_str() == other
491 }
492}
493
494impl PartialEq<&'_ str> for BytesStr {
495 fn eq(&self, other: &&str) -> bool {
496 self.as_str() == *other
497 }
498}
499
500impl PartialEq<Cow<'_, str>> for BytesStr {
501 fn eq(&self, other: &Cow<'_, str>) -> bool {
502 self.as_str() == *other
503 }
504}
505
506impl PartialEq<BytesStr> for str {
507 fn eq(&self, other: &BytesStr) -> bool {
508 self == other.as_str()
509 }
510}
511
512impl PartialEq<BytesStr> for &'_ str {
513 fn eq(&self, other: &BytesStr) -> bool {
514 *self == other.as_str()
515 }
516}
517
518impl PartialEq<BytesStr> for Bytes {
519 fn eq(&self, other: &BytesStr) -> bool {
520 *self == other.bytes
521 }
522}
523
524impl PartialEq<String> for BytesStr {
525 fn eq(&self, other: &String) -> bool {
526 self.as_str() == other
527 }
528}
529
530impl PartialEq<BytesStr> for String {
531 fn eq(&self, other: &BytesStr) -> bool {
532 self == other.as_str()
533 }
534}
535
536impl Ord for BytesStr {
537 fn cmp(&self, other: &Self) -> Ordering {
538 self.as_str().cmp(other.as_str())
539 }
540}
541
542impl PartialOrd for BytesStr {
543 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
544 Some(self.cmp(other))
545 }
546}
547
548impl Hash for BytesStr {
550 fn hash<H: Hasher>(&self, state: &mut H) {
551 self.as_str().hash(state);
552 }
553}
554
555impl TryFrom<&'static [u8]> for BytesStr {
556 type Error = Utf8Error;
557
558 fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> {
559 Self::from_static_utf8_slice(value)
560 }
561}
562
563#[cfg(feature = "serde")]
564mod serde_impl {
565 use serde::{Deserialize, Deserializer, Serialize, Serializer};
566
567 use super::*;
568
569 impl<'de> Deserialize<'de> for BytesStr {
570 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
571 where
572 D: Deserializer<'de>,
573 {
574 let s = String::deserialize(deserializer)?;
575 Ok(Self::from(s))
576 }
577 }
578
579 impl Serialize for BytesStr {
580 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
581 where
582 S: Serializer,
583 {
584 serializer.serialize_str(self.as_str())
585 }
586 }
587}
588
589#[cfg(test)]
590mod tests {
591 use std::{
592 borrow::{Borrow, Cow},
593 collections::{hash_map::DefaultHasher, HashMap},
594 ffi::OsStr,
595 hash::{Hash, Hasher},
596 path::Path,
597 };
598
599 use bytes::Bytes;
600
601 use super::*;
602 use crate::BytesString;
603
604 #[test]
605 fn test_new() {
606 let s = BytesStr::new();
607 assert_eq!(s.as_str(), "");
608 assert_eq!(s.len(), 0);
609 assert!(s.is_empty());
610 }
611
612 #[test]
613 fn test_default() {
614 let s: BytesStr = Default::default();
615 assert_eq!(s.as_str(), "");
616 assert_eq!(s.len(), 0);
617 assert!(s.is_empty());
618 }
619
620 #[test]
621 fn test_from_static() {
622 let s = BytesStr::from_static("hello world");
623 assert_eq!(s.as_str(), "hello world");
624 assert_eq!(s.len(), 11);
625 assert!(!s.is_empty());
626
627 let s = BytesStr::from_static("한국어 🌍");
629 assert_eq!(s.as_str(), "한국어 🌍");
630 }
631
632 #[test]
633 fn test_from_utf8() {
634 let bytes = Bytes::from_static(b"hello");
635 let s = BytesStr::from_utf8(bytes).unwrap();
636 assert_eq!(s.as_str(), "hello");
637
638 let bytes = Bytes::from("한국어".as_bytes());
640 let s = BytesStr::from_utf8(bytes).unwrap();
641 assert_eq!(s.as_str(), "한국어");
642
643 let invalid_bytes = Bytes::from_static(&[0xff, 0xfe]);
645 assert!(BytesStr::from_utf8(invalid_bytes).is_err());
646 }
647
648 #[test]
649 fn test_from_utf8_vec() {
650 let vec = b"hello world".to_vec();
651 let s = BytesStr::from_utf8_vec(vec).unwrap();
652 assert_eq!(s.as_str(), "hello world");
653
654 let vec = "한국어 🎉".as_bytes().to_vec();
656 let s = BytesStr::from_utf8_vec(vec).unwrap();
657 assert_eq!(s.as_str(), "한국어 🎉");
658
659 let invalid_vec = vec![0xff, 0xfe];
661 assert!(BytesStr::from_utf8_vec(invalid_vec).is_err());
662 }
663
664 #[test]
665 fn test_from_utf8_unchecked() {
666 let bytes = Bytes::from_static(b"hello");
667 let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
668 assert_eq!(s.as_str(), "hello");
669
670 let bytes = Bytes::from("한국어".as_bytes());
672 let s = unsafe { BytesStr::from_utf8_unchecked(bytes) };
673 assert_eq!(s.as_str(), "한국어");
674 }
675
676 #[test]
677 fn test_from_utf8_vec_unchecked() {
678 let vec = b"hello world".to_vec();
679 let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
680 assert_eq!(s.as_str(), "hello world");
681
682 let vec = "한국어 🎉".as_bytes().to_vec();
684 let s = unsafe { BytesStr::from_utf8_vec_unchecked(vec) };
685 assert_eq!(s.as_str(), "한국어 🎉");
686 }
687
688 #[test]
689 fn test_from_utf8_slice() {
690 let s = BytesStr::from_utf8_slice(b"hello").unwrap();
691 assert_eq!(s.as_str(), "hello");
692
693 let s = BytesStr::from_utf8_slice("한국어".as_bytes()).unwrap();
695 assert_eq!(s.as_str(), "한국어");
696
697 assert!(BytesStr::from_utf8_slice(&[0xff, 0xfe]).is_err());
699 }
700
701 #[test]
702 fn test_from_utf8_slice_unchecked() {
703 let s = unsafe { BytesStr::from_utf8_slice_unchecked(b"hello") };
704 assert_eq!(s.as_str(), "hello");
705
706 let s = unsafe { BytesStr::from_utf8_slice_unchecked("한국어".as_bytes()) };
708 assert_eq!(s.as_str(), "한국어");
709 }
710
711 #[test]
712 fn test_from_static_utf8_slice() {
713 let s = BytesStr::from_static_utf8_slice(b"hello").unwrap();
714 assert_eq!(s.as_str(), "hello");
715
716 let s = BytesStr::from_static_utf8_slice("한국어".as_bytes()).unwrap();
718 assert_eq!(s.as_str(), "한국어");
719
720 assert!(BytesStr::from_static_utf8_slice(&[0xff, 0xfe]).is_err());
722 }
723
724 #[test]
725 fn test_from_static_utf8_slice_unchecked() {
726 let s = unsafe { BytesStr::from_static_utf8_slice_unchecked(b"hello") };
727 assert_eq!(s.as_str(), "hello");
728
729 let s = unsafe { BytesStr::from_static_utf8_slice_unchecked("한국어".as_bytes()) };
731 assert_eq!(s.as_str(), "한국어");
732 }
733
734 #[test]
735 fn test_as_str() {
736 let s = BytesStr::from_static("hello world");
737 assert_eq!(s.as_str(), "hello world");
738
739 let s = BytesStr::from_static("한국어 🌍");
741 assert_eq!(s.as_str(), "한국어 🌍");
742 }
743
744 #[test]
745 fn test_deref() {
746 let s = BytesStr::from_static("hello world");
747
748 assert_eq!(s.len(), 11);
750 assert!(s.contains("world"));
751 assert!(s.starts_with("hello"));
752 assert!(s.ends_with("world"));
753 assert_eq!(&s[0..5], "hello");
754 }
755
756 #[test]
757 fn test_as_ref_str() {
758 let s = BytesStr::from_static("hello");
759 let str_ref: &str = s.as_ref();
760 assert_eq!(str_ref, "hello");
761 }
762
763 #[test]
764 fn test_as_ref_bytes() {
765 let s = BytesStr::from_static("hello");
766 let bytes_ref: &[u8] = s.as_ref();
767 assert_eq!(bytes_ref, b"hello");
768 }
769
770 #[test]
771 fn test_as_ref_bytes_type() {
772 let s = BytesStr::from_static("hello");
773 let bytes_ref: &Bytes = s.as_ref();
774 assert_eq!(bytes_ref.as_ref(), b"hello");
775 }
776
777 #[test]
778 fn test_as_ref_os_str() {
779 let s = BytesStr::from_static("hello/world");
780 let os_str_ref: &OsStr = s.as_ref();
781 assert_eq!(os_str_ref, OsStr::new("hello/world"));
782 }
783
784 #[test]
785 fn test_as_ref_path() {
786 let s = BytesStr::from_static("hello/world");
787 let path_ref: &Path = s.as_ref();
788 assert_eq!(path_ref, Path::new("hello/world"));
789 }
790
791 #[test]
792 fn test_borrow() {
793 let s = BytesStr::from_static("hello");
794 let borrowed: &str = s.borrow();
795 assert_eq!(borrowed, "hello");
796 }
797
798 #[test]
799 fn test_from_string() {
800 let original = String::from("hello world");
801 let s = BytesStr::from(original);
802 assert_eq!(s.as_str(), "hello world");
803 }
804
805 #[test]
806 fn test_from_static_str() {
807 let s = BytesStr::from("hello world");
808 assert_eq!(s.as_str(), "hello world");
809 }
810
811 #[test]
812 fn test_conversion_to_bytes_string() {
813 let s = BytesStr::from_static("hello");
814 let bytes_string: BytesString = s.into();
815 assert_eq!(bytes_string.as_str(), "hello");
816 }
817
818 #[test]
819 fn test_conversion_from_bytes_string() {
820 let mut bytes_string = BytesString::from("hello");
821 bytes_string.push_str(" world");
822 let s: BytesStr = bytes_string.into();
823 assert_eq!(s.as_str(), "hello world");
824 }
825
826 #[test]
827 fn test_try_from_static_slice() {
828 let s = BytesStr::try_from(b"hello" as &'static [u8]).unwrap();
829 assert_eq!(s.as_str(), "hello");
830
831 let invalid_slice: &'static [u8] = &[0xff, 0xfe];
833 assert!(BytesStr::try_from(invalid_slice).is_err());
834 }
835
836 #[test]
837 fn test_debug() {
838 let s = BytesStr::from_static("hello");
839 assert_eq!(format!("{:?}", s), "\"hello\"");
840
841 let s = BytesStr::from_static("hello\nworld");
842 assert_eq!(format!("{:?}", s), "\"hello\\nworld\"");
843 }
844
845 #[test]
846 fn test_display() {
847 let s = BytesStr::from_static("hello world");
848 assert_eq!(format!("{}", s), "hello world");
849
850 let s = BytesStr::from_static("한국어 🌍");
851 assert_eq!(format!("{}", s), "한국어 🌍");
852 }
853
854 #[test]
855 fn test_index() {
856 let s = BytesStr::from_static("hello world");
857 assert_eq!(&s[0..5], "hello");
858 assert_eq!(&s[6..], "world");
859 assert_eq!(&s[..5], "hello");
860 assert_eq!(&s[6..11], "world");
861
862 let s = BytesStr::from_static("한국어");
864 assert_eq!(&s[0..6], "한국");
865 }
866
867 #[test]
868 fn test_partial_eq_str() {
869 let s = BytesStr::from_static("hello");
870
871 assert_eq!(s, "hello");
873 assert_ne!(s, "world");
874
875 assert_eq!("hello", s);
877 assert_ne!("world", s);
878
879 let hello_str = "hello";
881 let world_str = "world";
882 assert_eq!(s, hello_str);
883 assert_ne!(s, world_str);
884
885 assert_eq!(hello_str, s);
887 assert_ne!(world_str, s);
888 }
889
890 #[test]
891 fn test_partial_eq_string() {
892 let s = BytesStr::from_static("hello");
893 let string = String::from("hello");
894 let other_string = String::from("world");
895
896 assert_eq!(s, string);
898 assert_ne!(s, other_string);
899
900 assert_eq!(string, s);
902 assert_ne!(other_string, s);
903 }
904
905 #[test]
906 fn test_partial_eq_cow() {
907 let s = BytesStr::from_static("hello");
908
909 assert_eq!(s, Cow::Borrowed("hello"));
910 assert_eq!(s, Cow::Owned(String::from("hello")));
911 assert_ne!(s, Cow::Borrowed("world"));
912 assert_ne!(s, Cow::Owned(String::from("world")));
913 }
914
915 #[test]
916 fn test_partial_eq_bytes() {
917 let s = BytesStr::from_static("hello");
918 let bytes = Bytes::from_static(b"hello");
919 let other_bytes = Bytes::from_static(b"world");
920
921 assert_eq!(bytes, s);
922 assert_ne!(other_bytes, s);
923 }
924
925 #[test]
926 fn test_partial_eq_bytes_str() {
927 let s1 = BytesStr::from_static("hello");
928 let s2 = BytesStr::from_static("hello");
929 let s3 = BytesStr::from_static("world");
930
931 assert_eq!(s1, s2);
932 assert_ne!(s1, s3);
933 }
934
935 #[test]
936 fn test_ordering() {
937 let s1 = BytesStr::from_static("apple");
938 let s2 = BytesStr::from_static("banana");
939 let s3 = BytesStr::from_static("apple");
940
941 assert!(s1 < s2);
942 assert!(s2 > s1);
943 assert_eq!(s1, s3);
944 assert!(s1 <= s3);
945 assert!(s1 >= s3);
946
947 assert_eq!(s1.partial_cmp(&s2), Some(std::cmp::Ordering::Less));
949 assert_eq!(s2.partial_cmp(&s1), Some(std::cmp::Ordering::Greater));
950 assert_eq!(s1.partial_cmp(&s3), Some(std::cmp::Ordering::Equal));
951 }
952
953 #[test]
954 fn test_hash() {
955 let s1 = BytesStr::from_static("hello");
956 let s2 = BytesStr::from_static("hello");
957 let s3 = BytesStr::from_static("world");
958
959 let mut hasher1 = DefaultHasher::new();
960 let mut hasher2 = DefaultHasher::new();
961 let mut hasher3 = DefaultHasher::new();
962
963 s1.hash(&mut hasher1);
964 s2.hash(&mut hasher2);
965 s3.hash(&mut hasher3);
966
967 assert_eq!(hasher1.finish(), hasher2.finish());
968 assert_ne!(hasher1.finish(), hasher3.finish());
969
970 let mut str_hasher = DefaultHasher::new();
972 "hello".hash(&mut str_hasher);
973 assert_eq!(hasher1.finish(), str_hasher.finish());
974 }
975
976 #[test]
977 fn test_clone() {
978 let s1 = BytesStr::from_static("hello world");
979 let s2 = s1.clone();
980
981 assert_eq!(s1, s2);
982 assert_eq!(s1.as_str(), s2.as_str());
983
984 }
987
988 #[test]
989 fn test_extend_bytes_string() {
990 let mut bytes_string = BytesString::from("hello");
991 let parts = vec![
992 BytesStr::from_static(" "),
993 BytesStr::from_static("world"),
994 BytesStr::from_static("!"),
995 ];
996
997 bytes_string.extend(parts);
998 assert_eq!(bytes_string.as_str(), "hello world!");
999 }
1000
1001 #[test]
1002 fn test_unicode_handling() {
1003 let s = BytesStr::from_static("Hello 🌍 한국어 🎉");
1004 assert_eq!(s.as_str(), "Hello 🌍 한국어 🎉");
1005 assert!(s.len() > 13); let korean = BytesStr::from_static("한국어");
1009 assert_eq!(korean.len(), 9); assert_eq!(&korean[0..6], "한국"); }
1012
1013 #[test]
1014 fn test_empty_strings() {
1015 let s = BytesStr::new();
1016 assert!(s.is_empty());
1017 assert_eq!(s.len(), 0);
1018 assert_eq!(s.as_str(), "");
1019
1020 let s = BytesStr::from_static("");
1021 assert!(s.is_empty());
1022 assert_eq!(s.len(), 0);
1023 assert_eq!(s.as_str(), "");
1024 }
1025
1026 #[test]
1027 fn test_large_strings() {
1028 let large_str = "a".repeat(10000);
1029 let s = BytesStr::from(large_str.clone());
1030 assert_eq!(s.len(), 10000);
1031 assert_eq!(s.as_str(), large_str);
1032 }
1033
1034 #[test]
1035 fn test_hash_map_usage() {
1036 let mut map = HashMap::new();
1037 let key = BytesStr::from_static("key");
1038 map.insert(key, "value");
1039
1040 let lookup_key = BytesStr::from_static("key");
1041 assert_eq!(map.get(&lookup_key), Some(&"value"));
1042
1043 assert_eq!(map.get("key"), Some(&"value"));
1045 }
1046
1047 #[test]
1048 fn test_memory_efficiency() {
1049 let original = BytesStr::from(String::from("hello world"));
1051 let clone1 = original.clone();
1052 let clone2 = original.clone();
1053
1054 assert_eq!(original.as_str(), "hello world");
1056 assert_eq!(clone1.as_str(), "hello world");
1057 assert_eq!(clone2.as_str(), "hello world");
1058
1059 assert_eq!(original, clone1);
1061 assert_eq!(clone1, clone2);
1062 }
1063
1064 #[test]
1065 fn test_static_vs_owned() {
1066 let static_str = BytesStr::from_static("hello");
1068 assert_eq!(static_str.as_str(), "hello");
1069
1070 let owned_str = BytesStr::from(String::from("hello"));
1072 assert_eq!(owned_str.as_str(), "hello");
1073
1074 assert_eq!(static_str, owned_str);
1076 }
1077
1078 #[test]
1079 fn test_error_cases() {
1080 let invalid_sequences = vec![
1082 vec![0xff], vec![0xfe, 0xff], vec![0xc0, 0x80], vec![0xe0, 0x80, 0x80], ];
1087
1088 for invalid in invalid_sequences {
1089 assert!(BytesStr::from_utf8(Bytes::from(invalid.clone())).is_err());
1090 assert!(BytesStr::from_utf8_vec(invalid.clone()).is_err());
1091 assert!(BytesStr::from_utf8_slice(&invalid).is_err());
1092 }
1093 }
1094
1095 #[test]
1096 fn test_boundary_conditions() {
1097 let s = BytesStr::from_static("a");
1099 assert_eq!(s.len(), 1);
1100 assert_eq!(s.as_str(), "a");
1101
1102 let s = BytesStr::from_static("한");
1104 assert_eq!(s.len(), 3); assert_eq!(s.as_str(), "한");
1106
1107 let s = BytesStr::from_static("🌍");
1109 assert_eq!(s.len(), 4); assert_eq!(s.as_str(), "🌍");
1111 }
1112}