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#[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 unsafe fn from_utf8_unchecked(bytes: Bytes) -> Self {
125 Self { bytes }
126 }
127
128 pub unsafe fn from_utf8_vec_unchecked(bytes: Vec<u8>) -> Self {
137 Self::from_utf8_unchecked(Bytes::from(bytes))
138 }
139
140 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 pub unsafe fn from_utf8_slice_unchecked(bytes: &[u8]) -> Self {
169 Self {
170 bytes: Bytes::copy_from_slice(bytes),
171 }
172 }
173
174 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 pub unsafe fn from_static_utf8_slice_unchecked(bytes: &'static [u8]) -> Self {
202 Self {
203 bytes: Bytes::from_static(bytes),
204 }
205 }
206
207 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
388impl 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 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 let bytes = Bytes::from("한국어".as_bytes());
480 let s = BytesStr::from_utf8(bytes).unwrap();
481 assert_eq!(s.as_str(), "한국어");
482
483 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 let vec = "한국어 🎉".as_bytes().to_vec();
496 let s = BytesStr::from_utf8_vec(vec).unwrap();
497 assert_eq!(s.as_str(), "한국어 🎉");
498
499 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 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 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 let s = BytesStr::from_utf8_slice("한국어".as_bytes()).unwrap();
535 assert_eq!(s.as_str(), "한국어");
536
537 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 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 let s = BytesStr::from_static_utf8_slice("한국어".as_bytes()).unwrap();
558 assert_eq!(s.as_str(), "한국어");
559
560 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 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 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 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 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 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 assert_eq!(s, "hello");
713 assert_ne!(s, "world");
714
715 assert_eq!("hello", s);
717 assert_ne!("world", s);
718
719 let hello_str = "hello";
721 let world_str = "world";
722 assert_eq!(s, hello_str);
723 assert_ne!(s, world_str);
724
725 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 assert_eq!(s, string);
738 assert_ne!(s, other_string);
739
740 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 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 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 }
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); let korean = BytesStr::from_static("한국어");
849 assert_eq!(korean.len(), 9); assert_eq!(&korean[0..6], "한국"); }
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 assert_eq!(map.get("key"), Some(&"value"));
885 }
886
887 #[test]
888 fn test_memory_efficiency() {
889 let original = BytesStr::from(String::from("hello world"));
891 let clone1 = original.clone();
892 let clone2 = original.clone();
893
894 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 assert_eq!(original, clone1);
901 assert_eq!(clone1, clone2);
902 }
903
904 #[test]
905 fn test_static_vs_owned() {
906 let static_str = BytesStr::from_static("hello");
908 assert_eq!(static_str.as_str(), "hello");
909
910 let owned_str = BytesStr::from(String::from("hello"));
912 assert_eq!(owned_str.as_str(), "hello");
913
914 assert_eq!(static_str, owned_str);
916 }
917
918 #[test]
919 fn test_error_cases() {
920 let invalid_sequences = vec![
922 vec![0xff], vec![0xfe, 0xff], vec![0xc0, 0x80], vec![0xe0, 0x80, 0x80], ];
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 let s = BytesStr::from_static("a");
939 assert_eq!(s.len(), 1);
940 assert_eq!(s.as_str(), "a");
941
942 let s = BytesStr::from_static("한");
944 assert_eq!(s.len(), 3); assert_eq!(s.as_str(), "한");
946
947 let s = BytesStr::from_static("🌍");
949 assert_eq!(s.len(), 4); assert_eq!(s.as_str(), "🌍");
951 }
952}