1use super::{
2 iter::{
3 MatchIndicesInternal, MatchesInternal, SearcherIterator, SearcherIteratorRev,
4 SplitInclusiveInternal, SplitInternal, SplitNInternal,
5 },
6 pattern::{Pattern, ReverseSearcher, SearchStep, Searcher, StrSearcher},
7};
8use std::{
9 borrow::{Borrow, Cow},
10 error::Error,
11 ffi::OsStr,
12 fmt::{Debug, Display},
13 hash::Hash,
14 ops::{Add, Deref, RangeBounds},
15 path::{Path, PathBuf},
16 rc::Rc,
17 str::FromStr,
18 sync::Arc,
19};
20
21#[doc(hidden)]
22#[cfg(any(
23 not(feature = "stack"),
24 target_pointer_width = "16",
25 target_pointer_width = "32"
26))]
27#[path = "normal.rs"]
28mod internal;
29#[doc(hidden)]
30#[cfg(not(any(
31 not(feature = "stack"),
32 target_pointer_width = "16",
33 target_pointer_width = "32"
34)))]
35#[path = "stack.rs"]
36mod internal;
37
38pub use self::internal::FastStr;
39
40unsafe impl Sync for FastStr {}
41unsafe impl Send for FastStr {}
42
43impl FastStr {
44 pub fn repeat(&self, n: usize) -> Self {
55 if n == 1 {
56 self.clone()
57 } else {
58 Self::from_string(self.as_str().repeat(n))
59 }
60 }
61
62 #[inline]
82 pub fn to_ascii_uppercase(&self) -> Self {
83 Self::from_string(self.as_str().to_ascii_uppercase())
84 }
85
86 #[inline]
106 pub fn to_ascii_lowercase(&self) -> Self {
107 Self::from_string(self.as_str().to_ascii_lowercase())
108 }
109
110 #[inline]
147 pub fn to_uppercase(&self) -> Self {
148 Self::from_string(self.as_str().to_uppercase())
149 }
150
151 #[inline]
194 pub fn to_lowercase(&self) -> Self {
195 Self::from_string(self.as_str().to_lowercase())
196 }
197
198 #[inline]
210 pub fn as_bytes(&self) -> &[u8] {
211 self.as_str().as_bytes()
212 }
213
214 pub fn slice<R>(&self, range: R) -> Self
227 where
228 R: RangeBounds<usize>,
229 {
230 use std::ops::Bound;
231
232 self.do_sub_with(|str, wrapper| {
233 let len = str.len();
234
235 let start = match range.start_bound() {
236 Bound::Included(&n) => std::cmp::max(0, n),
237 Bound::Excluded(&n) => std::cmp::max(0, n + 1),
238 Bound::Unbounded => 0,
239 };
240
241 let end = match range.end_bound() {
242 Bound::Included(&n) => std::cmp::min(len, n + 1),
243 Bound::Excluded(&n) => std::cmp::min(len, n),
244 Bound::Unbounded => len,
245 };
246
247 wrapper(&str[start..end])
248 })
249 }
250
251 #[inline]
267 pub fn trim(&self) -> Self {
268 self.do_sub_with(|str, wrapper| wrapper(str.trim()))
269 }
270
271 #[inline]
272 pub fn trim_into(self) -> Self {
273 self.do_sub_into(|str| str.trim())
274 }
275
276 #[inline]
298 pub fn trim_start(&self) -> Self {
299 self.do_sub_with(|str, wrapper| wrapper(str.trim_start()))
300 }
301
302 #[inline]
303 pub fn trim_start_into(self) -> Self {
304 self.do_sub_into(|str| str.trim_start())
305 }
306
307 #[inline]
330 pub fn trim_end(&self) -> Self {
331 self.do_sub_with(|str, wrapper| wrapper(str.trim_end()))
332 }
333
334 #[inline]
335 pub fn trim_end_into(self) -> Self {
336 self.do_sub_into(|str| str.trim_end())
337 }
338
339 pub fn matches<'a, P: Pattern<'a> + 'a>(
359 &'a self,
360 pat: P,
361 ) -> impl Iterator<Item = FastStr> + 'a {
362 self.do_sub_with(move |str, wrapper| {
363 SearcherIterator::new(MatchesInternal::<P>::new(pat.into_searcher(str))).map(wrapper)
364 })
365 }
366
367 pub fn match_indices<'a, P: Pattern<'a> + 'a>(
386 &'a self,
387 pat: P,
388 ) -> impl Iterator<Item = (usize, FastStr)> + 'a {
389 self.do_sub_with(move |str, wrapper| {
390 SearcherIterator::new(MatchIndicesInternal::<P>::new(pat.into_searcher(str)))
391 .map(move |(i, str)| (i, wrapper(str)))
392 })
393 }
394
395 pub fn rmatches<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a
411 where
412 P::Searcher: ReverseSearcher<'a>,
413 {
414 self.do_sub_with(move |str, wrapper| {
415 SearcherIteratorRev::new(MatchesInternal::<P>::new(pat.into_searcher(str))).map(wrapper)
416 })
417 }
418
419 pub fn rmatch_indices<'a, P: Pattern<'a> + 'a>(
438 &'a self,
439 pat: P,
440 ) -> impl Iterator<Item = (usize, FastStr)> + 'a
441 where
442 P::Searcher: ReverseSearcher<'a>,
443 {
444 self.do_sub_with(move |str, wrapper| {
445 SearcherIteratorRev::new(MatchIndicesInternal::<P>::new(pat.into_searcher(str)))
446 .map(move |(i, str)| (i, wrapper(str)))
447 })
448 }
449
450 pub fn replace<'a, P: Pattern<'a> + 'a, To: AsRef<str>>(&'a self, from: P, to: To) -> FastStr {
476 let mut result = String::with_capacity(32);
477 let mut last_end = 0;
478 let to = to.as_ref();
479 let str = self.as_str();
480 for (start, part) in
481 SearcherIterator::new(MatchIndicesInternal::<P>::new(from.into_searcher(str)))
482 {
483 result.push_str(unsafe { str.get_unchecked(last_end..start) });
484 result.push_str(to);
485 last_end = start + part.len();
486 }
487 result.push_str(unsafe { str.get_unchecked(last_end..str.len()) });
488 result.into()
489 }
490
491 pub fn replacen<'a, P: Pattern<'a> + 'a, To: AsRef<str>>(
517 &'a self,
518 from: P,
519 to: To,
520 count: usize,
521 ) -> FastStr {
522 let mut result = String::with_capacity(32);
523 let mut last_end = 0;
524 let to = to.as_ref();
525 let str = self.as_str();
526 for (start, part) in
527 SearcherIterator::new(MatchIndicesInternal::<P>::new(from.into_searcher(str)))
528 .take(count)
529 {
530 result.push_str(unsafe { str.get_unchecked(last_end..start) });
531 result.push_str(to);
532 last_end = start + part.len();
533 }
534 result.push_str(unsafe { str.get_unchecked(last_end..str.len()) });
535 result.into()
536 }
537
538 pub fn split<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a {
541 self.do_sub_with(move |str, wrapper| {
542 SearcherIterator::new(SplitInternal::<P> {
543 start: 0,
544 end: str.len(),
545 matcher: pat.into_searcher(str),
546 allow_trailing_empty: true,
547 finished: false,
548 })
549 .map(wrapper)
550 })
551 }
552
553 pub fn splitn<'a, P: Pattern<'a> + 'a>(
554 &'a self,
555 n: usize,
556 pat: P,
557 ) -> impl Iterator<Item = FastStr> + 'a {
558 self.do_sub_with(move |str, wrapper| {
559 SearcherIterator::new(SplitNInternal::<P> {
560 iter: SplitInternal {
561 start: 0,
562 end: str.len(),
563 matcher: pat.into_searcher(str),
564 allow_trailing_empty: true,
565 finished: false,
566 },
567 count: n,
568 })
569 .map(wrapper)
570 })
571 }
572
573 pub fn split_terminator<'a, P: Pattern<'a> + 'a>(
574 &'a self,
575 pat: P,
576 ) -> impl Iterator<Item = FastStr> + 'a {
577 self.do_sub_with(move |str, wrapper| {
578 SearcherIterator::new(SplitInternal::<P> {
579 start: 0,
580 end: str.len(),
581 matcher: pat.into_searcher(str),
582 allow_trailing_empty: false,
583 finished: false,
584 })
585 .map(wrapper)
586 })
587 }
588
589 pub fn split_inclusive<'a, P: Pattern<'a> + 'a>(
594 &'a self,
595 pat: P,
596 ) -> impl Iterator<Item = FastStr> + 'a {
597 self.do_sub_with(move |str, wrapper| {
598 SearcherIterator::new(SplitInclusiveInternal::<P>(SplitInternal {
599 start: 0,
600 end: str.len(),
601 matcher: pat.into_searcher(str),
602 allow_trailing_empty: false,
603 finished: false,
604 }))
605 .map(wrapper)
606 })
607 }
608
609 pub fn split_whitespace<'a>(&'a self) -> impl Iterator<Item = FastStr> + 'a {
610 self.split(char::is_whitespace)
611 .filter(|str| !str.is_empty())
612 }
613
614 pub fn split_ascii_whitespace<'a>(&'a self) -> impl Iterator<Item = FastStr> + 'a {
615 self.do_sub_with(move |str, wrapper| {
616 str.as_bytes()
617 .split(u8::is_ascii_whitespace)
618 .filter(|bytes| !bytes.is_empty())
619 .map(move |bytes| wrapper(unsafe { std::str::from_utf8_unchecked(bytes) }))
620 })
621 }
622
623 pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(FastStr, FastStr)> {
624 self.do_sub_with(move |str, wrapper| {
625 let (start, end) = delimiter.into_searcher(str).next_match()?;
626 unsafe {
628 Some((
629 wrapper(str.get_unchecked(..start)),
630 wrapper(str.get_unchecked(end..)),
631 ))
632 }
633 })
634 }
635
636 pub fn split_at(&self, mid: usize) -> (FastStr, FastStr) {
637 self.do_sub_with(move |str, wrapper| {
638 if str.is_char_boundary(mid) {
640 unsafe {
642 (
643 wrapper(str.get_unchecked(0..mid)),
644 wrapper(str.get_unchecked(mid..str.len())),
645 )
646 }
647 } else {
648 panic!("failed to slice string");
649 }
650 })
651 }
652
653 pub fn rsplit<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a
654 where
655 P::Searcher: ReverseSearcher<'a>,
656 {
657 self.do_sub_with(move |str, wrapper| {
658 SearcherIteratorRev::new(SplitInternal::<P> {
659 start: 0,
660 end: str.len(),
661 matcher: pat.into_searcher(str),
662 allow_trailing_empty: true,
663 finished: false,
664 })
665 .map(wrapper)
666 })
667 }
668
669 pub fn rsplitn<'a, P: Pattern<'a> + 'a>(
670 &'a self,
671 n: usize,
672 pat: P,
673 ) -> impl Iterator<Item = FastStr> + 'a
674 where
675 P::Searcher: ReverseSearcher<'a>,
676 {
677 self.do_sub_with(move |str, wrapper| {
678 SearcherIteratorRev::new(SplitNInternal::<P> {
679 iter: SplitInternal {
680 start: 0,
681 end: str.len(),
682 matcher: pat.into_searcher(str),
683 allow_trailing_empty: true,
684 finished: false,
685 },
686 count: n,
687 })
688 .map(wrapper)
689 })
690 }
691
692 pub fn rsplit_terminator<'a, P: Pattern<'a> + 'a>(
693 &'a self,
694 pat: P,
695 ) -> impl Iterator<Item = FastStr> + 'a
696 where
697 P::Searcher: ReverseSearcher<'a>,
698 {
699 self.do_sub_with(move |str, wrapper| {
700 SearcherIteratorRev::new(SplitInternal::<P> {
701 start: 0,
702 end: str.len(),
703 matcher: pat.into_searcher(str),
704 allow_trailing_empty: false,
705 finished: false,
706 })
707 .map(wrapper)
708 })
709 }
710
711 pub fn rsplit_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(FastStr, FastStr)>
712 where
713 P::Searcher: ReverseSearcher<'a>,
714 {
715 self.do_sub_with(move |str, wrapper| {
716 let (start, end) = delimiter.into_searcher(str).next_match_back()?;
717 unsafe {
719 Some((
720 wrapper(str.get_unchecked(..start)),
721 wrapper(str.get_unchecked(end..)),
722 ))
723 }
724 })
725 }
726
727 pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<FastStr> {
743 self.do_sub_with(|str, wrapper| prefix.strip_prefix_of(str).map(wrapper))
744 }
745
746 pub fn strip_suffix<'a, P: Pattern<'a>>(&'a self, suffix: P) -> Option<FastStr>
762 where
763 P::Searcher: ReverseSearcher<'a>,
764 {
765 self.do_sub_with(|str, wrapper| suffix.strip_suffix_of(str).map(wrapper))
766 }
767}
768
769impl Default for FastStr {
770 #[inline]
771 fn default() -> Self {
772 Self::new()
773 }
774}
775
776impl Default for &FastStr {
777 #[inline]
778 fn default() -> Self {
779 const FAST_STR_DEFAULT: &FastStr = &FastStr::new();
780 FAST_STR_DEFAULT
781 }
782}
783
784impl Deref for FastStr {
785 type Target = str;
786
787 #[inline]
788 fn deref(&self) -> &Self::Target {
789 self.as_str()
790 }
791}
792
793impl Borrow<str> for FastStr {
794 #[inline]
795 fn borrow(&self) -> &str {
796 self.as_str()
797 }
798}
799
800impl AsRef<str> for FastStr {
801 #[inline]
802 fn as_ref(&self) -> &str {
803 self.as_str()
804 }
805}
806
807impl AsRef<[u8]> for FastStr {
808 #[inline]
809 fn as_ref(&self) -> &[u8] {
810 self.as_str().as_ref()
811 }
812}
813
814impl AsRef<Path> for FastStr {
815 #[inline]
816 fn as_ref(&self) -> &Path {
817 self.as_str().as_ref()
818 }
819}
820
821impl AsRef<OsStr> for FastStr {
822 #[inline]
823 fn as_ref(&self) -> &OsStr {
824 self.as_str().as_ref()
825 }
826}
827
828impl Hash for FastStr {
829 #[inline]
830 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
831 self.as_str().hash(state)
832 }
833}
834
835impl Eq for FastStr {}
836
837impl PartialEq for FastStr {
838 #[inline]
839 fn eq(&self, other: &Self) -> bool {
840 PartialEq::eq(self, other.as_str())
841 }
842}
843
844impl PartialEq<&FastStr> for FastStr {
845 #[inline]
846 fn eq(&self, other: &&FastStr) -> bool {
847 PartialEq::eq(self, *other)
848 }
849}
850
851impl PartialEq<str> for FastStr {
852 #[inline]
853 fn eq(&self, other: &str) -> bool {
854 let this = self.as_str();
855 std::ptr::eq(std::ptr::addr_of!(*this), std::ptr::addr_of!(*other))
856 || PartialEq::eq(this, other)
857 }
858}
859
860impl PartialEq<FastStr> for str {
861 #[inline]
862 fn eq(&self, other: &FastStr) -> bool {
863 PartialEq::eq(other, self)
864 }
865}
866
867impl PartialEq<&str> for FastStr {
868 #[inline]
869 fn eq(&self, other: &&str) -> bool {
870 PartialEq::eq(self, *other)
871 }
872}
873
874impl PartialEq<FastStr> for &str {
875 #[inline]
876 fn eq(&self, other: &FastStr) -> bool {
877 PartialEq::eq(other, *self)
878 }
879}
880
881impl PartialEq<&FastStr> for str {
882 #[inline]
883 fn eq(&self, other: &&FastStr) -> bool {
884 PartialEq::eq(*other, self)
885 }
886}
887
888impl PartialEq<String> for FastStr {
889 #[inline]
890 fn eq(&self, other: &String) -> bool {
891 PartialEq::eq(self.as_str(), other.as_str())
892 }
893}
894
895impl PartialEq<FastStr> for String {
896 #[inline]
897 fn eq(&self, other: &FastStr) -> bool {
898 PartialEq::eq(other, self)
899 }
900}
901
902impl PartialEq<&String> for FastStr {
903 #[inline]
904 fn eq(&self, other: &&String) -> bool {
905 PartialEq::eq(self.as_str(), other.as_str())
906 }
907}
908
909impl PartialEq<FastStr> for &String {
910 #[inline]
911 fn eq(&self, other: &FastStr) -> bool {
912 PartialEq::eq(other, self)
913 }
914}
915
916impl Ord for FastStr {
917 #[inline]
918 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
919 let str1 = self.as_str();
920 let str2 = other.as_str();
921 if std::ptr::eq(std::ptr::addr_of!(*str1), std::ptr::addr_of!(*str2)) {
922 return std::cmp::Ordering::Equal;
923 }
924 Ord::cmp(str1, str2)
925 }
926}
927
928impl PartialOrd for FastStr {
929 #[inline]
930 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
931 PartialOrd::partial_cmp(self, other.as_str())
932 }
933}
934
935impl PartialOrd<&FastStr> for FastStr {
936 #[inline]
937 fn partial_cmp(&self, other: &&FastStr) -> Option<std::cmp::Ordering> {
938 PartialOrd::partial_cmp(self, *other)
939 }
940}
941
942impl PartialOrd<str> for FastStr {
943 #[inline]
944 fn partial_cmp(&self, other: &str) -> Option<std::cmp::Ordering> {
945 let str1 = self.as_str();
946 let str2 = other;
947 if std::ptr::eq(std::ptr::addr_of!(*str1), std::ptr::addr_of!(*str2)) {
948 return Some(std::cmp::Ordering::Equal);
949 }
950 PartialOrd::partial_cmp(self.as_str(), other)
951 }
952}
953
954impl PartialOrd<FastStr> for str {
955 #[inline]
956 fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
957 PartialOrd::partial_cmp(other, self)
958 }
959}
960
961impl PartialOrd<&str> for FastStr {
962 #[inline]
963 fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> {
964 PartialOrd::partial_cmp(self.as_str(), *other)
965 }
966}
967
968impl PartialOrd<&FastStr> for str {
969 #[inline]
970 fn partial_cmp(&self, other: &&FastStr) -> Option<std::cmp::Ordering> {
971 PartialOrd::partial_cmp(*other, self)
972 }
973}
974
975impl PartialOrd<FastStr> for &str {
976 #[inline]
977 fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
978 PartialOrd::partial_cmp(other, *self)
979 }
980}
981
982impl PartialOrd<String> for FastStr {
983 #[inline]
984 fn partial_cmp(&self, other: &String) -> Option<std::cmp::Ordering> {
985 PartialOrd::partial_cmp(self.as_str(), other.as_str())
986 }
987}
988
989impl PartialOrd<FastStr> for String {
990 #[inline]
991 fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
992 PartialOrd::partial_cmp(other, self)
993 }
994}
995
996impl PartialOrd<&String> for FastStr {
997 #[inline]
998 fn partial_cmp(&self, other: &&String) -> Option<std::cmp::Ordering> {
999 PartialOrd::partial_cmp(self.as_str(), other.as_str())
1000 }
1001}
1002
1003impl PartialOrd<FastStr> for &String {
1004 #[inline]
1005 fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
1006 PartialOrd::partial_cmp(other, *self)
1007 }
1008}
1009
1010impl Debug for FastStr {
1011 #[inline]
1012 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1013 Debug::fmt(self.as_str(), f)
1014 }
1015}
1016
1017impl Display for FastStr {
1018 #[inline]
1019 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1020 Display::fmt(self.as_str(), f)
1021 }
1022}
1023
1024#[cfg(feature = "serde")]
1025impl serde::Serialize for FastStr {
1026 #[inline]
1027 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1028 where
1029 S: serde::Serializer,
1030 {
1031 serde::Serialize::serialize(self.as_str(), serializer)
1032 }
1033}
1034
1035#[cfg(feature = "serde")]
1036impl<'de> serde::Deserialize<'de> for FastStr {
1037 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1038 where
1039 D: serde::Deserializer<'de>,
1040 {
1041 let result = <String as serde::Deserialize>::deserialize(deserializer);
1042
1043 match result {
1044 Ok(ok) => Ok(Self::from_string(ok)),
1045 Err(err) => Err(err),
1046 }
1047 }
1048}
1049
1050impl FromStr for FastStr {
1051 type Err = <String as FromStr>::Err;
1052
1053 #[inline]
1054 fn from_str(s: &str) -> Result<Self, Self::Err> {
1055 let result = FromStr::from_str(s);
1056 match result {
1057 Ok(ok) => Ok(Self::from_string(ok)),
1058 Err(err) => Err(err),
1059 }
1060 }
1061}
1062
1063impl TryFrom<&[u8]> for FastStr {
1064 type Error = std::str::Utf8Error;
1065
1066 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
1067 std::str::from_utf8(value).map(Self::from_ref)
1068 }
1069}
1070
1071impl TryFrom<Vec<u8>> for FastStr {
1072 type Error = std::string::FromUtf8Error;
1073
1074 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
1075 String::from_utf8(value).map(Self::from_string)
1076 }
1077}
1078
1079impl From<&&str> for FastStr {
1080 #[inline]
1081 fn from(str: &&str) -> Self {
1082 Self::from_ref(*str)
1083 }
1084}
1085
1086impl From<&'static str> for FastStr {
1087 #[inline]
1088 fn from(str: &'static str) -> Self {
1089 Self::from_static(str)
1090 }
1091}
1092
1093impl From<&mut str> for FastStr {
1094 #[inline]
1095 fn from(str: &mut str) -> Self {
1096 Self::from_ref(str)
1097 }
1098}
1099
1100impl From<Rc<str>> for FastStr {
1101 #[inline]
1102 fn from(str: Rc<str>) -> Self {
1103 Self::from_ref(str.as_ref())
1104 }
1105}
1106
1107impl From<Arc<str>> for FastStr {
1108 #[inline]
1109 fn from(str: Arc<str>) -> Self {
1110 Self::from_ref(str.as_ref())
1111 }
1112}
1113
1114impl From<Box<str>> for FastStr {
1115 #[inline]
1116 fn from(str: Box<str>) -> Self {
1117 Self::from_string(str.into())
1118 }
1119}
1120
1121impl From<String> for FastStr {
1122 #[inline]
1123 fn from(str: String) -> Self {
1124 Self::from_string(str)
1125 }
1126}
1127
1128impl From<&String> for FastStr {
1129 #[inline]
1130 fn from(str: &String) -> Self {
1131 Self::from_ref(str)
1132 }
1133}
1134
1135impl From<&FastStr> for FastStr {
1136 #[inline]
1137 fn from(str: &FastStr) -> Self {
1138 str.clone()
1139 }
1140}
1141
1142impl From<Cow<'_, str>> for FastStr {
1143 #[inline]
1144 fn from(str: Cow<'_, str>) -> Self {
1145 Self::from_string(str.into_owned())
1146 }
1147}
1148
1149impl From<&Cow<'_, str>> for FastStr {
1150 #[inline]
1151 fn from(str: &Cow<'_, str>) -> Self {
1152 Self::from_ref(str.as_ref())
1153 }
1154}
1155
1156impl From<Cow<'_, String>> for FastStr {
1157 #[inline]
1158 fn from(str: Cow<'_, String>) -> Self {
1159 Self::from_string(str.into_owned())
1160 }
1161}
1162
1163impl From<&Cow<'_, String>> for FastStr {
1164 #[inline]
1165 fn from(str: &Cow<'_, String>) -> Self {
1166 Self::from_ref(str.as_ref())
1167 }
1168}
1169
1170impl From<()> for FastStr {
1171 #[inline]
1172 fn from(_: ()) -> Self {
1173 Self::new()
1174 }
1175}
1176
1177impl From<&()> for FastStr {
1178 #[inline]
1179 fn from(_: &()) -> Self {
1180 Self::new()
1181 }
1182}
1183
1184impl From<bool> for FastStr {
1185 #[inline]
1186 fn from(b: bool) -> Self {
1187 Self::from_static(if b { "true" } else { "false" })
1188 }
1189}
1190
1191impl From<&bool> for FastStr {
1192 #[inline]
1193 fn from(b: &bool) -> Self {
1194 Self::from(*b)
1195 }
1196}
1197
1198impl From<FastStr> for String {
1199 #[inline]
1200 fn from(str: FastStr) -> Self {
1201 str.into_string()
1202 }
1203}
1204
1205impl From<FastStr> for PathBuf {
1206 #[inline]
1207 fn from(str: FastStr) -> Self {
1208 str.into_string().into()
1209 }
1210}
1211
1212impl From<FastStr> for Box<str> {
1213 #[inline]
1214 fn from(str: FastStr) -> Self {
1215 str.into_string().into()
1216 }
1217}
1218
1219impl From<&FastStr> for Box<str> {
1220 #[inline]
1221 fn from(str: &FastStr) -> Self {
1222 str.as_str().into()
1223 }
1224}
1225
1226impl From<FastStr> for Rc<str> {
1227 #[inline]
1228 fn from(str: FastStr) -> Self {
1229 str.as_str().into()
1230 }
1231}
1232
1233impl From<&FastStr> for Rc<str> {
1234 #[inline]
1235 fn from(str: &FastStr) -> Self {
1236 str.as_str().into()
1237 }
1238}
1239
1240impl From<FastStr> for Arc<str> {
1241 #[inline]
1242 fn from(str: FastStr) -> Self {
1243 str.as_str().into()
1244 }
1245}
1246
1247impl From<&FastStr> for Arc<str> {
1248 #[inline]
1249 fn from(str: &FastStr) -> Self {
1250 str.as_str().into()
1251 }
1252}
1253
1254impl From<FastStr> for Vec<u8> {
1255 #[inline]
1256 fn from(str: FastStr) -> Self {
1257 str.into_string().into()
1258 }
1259}
1260
1261impl From<&FastStr> for Vec<u8> {
1262 #[inline]
1263 fn from(str: &FastStr) -> Self {
1264 str.as_str().into()
1265 }
1266}
1267
1268impl From<FastStr> for Box<dyn Error + 'static> {
1269 fn from(str: FastStr) -> Self {
1270 str.into_string().into()
1271 }
1272}
1273
1274impl From<FastStr> for Box<dyn Error + Send + Sync + 'static> {
1275 fn from(str: FastStr) -> Self {
1276 str.into_string().into()
1277 }
1278}
1279
1280impl From<&FastStr> for Box<dyn Error + 'static> {
1281 fn from(str: &FastStr) -> Self {
1282 str.as_str().into()
1283 }
1284}
1285
1286impl From<&FastStr> for Box<dyn Error + Send + Sync + 'static> {
1287 fn from(str: &FastStr) -> Self {
1288 str.as_str().into()
1289 }
1290}
1291
1292impl<'a> From<FastStr> for Cow<'a, str> {
1293 fn from(str: FastStr) -> Self {
1294 if let Some(str) = str.static_str() {
1295 Cow::Borrowed(str)
1296 } else {
1297 Cow::Owned(str.into_string())
1298 }
1299 }
1300}
1301
1302impl<'a> From<&'a FastStr> for Cow<'a, str> {
1303 #[inline]
1304 fn from(str: &'a FastStr) -> Self {
1305 Cow::Borrowed(str.as_str())
1306 }
1307}
1308
1309impl From<&FastStr> for String {
1310 #[inline]
1311 fn from(str: &FastStr) -> Self {
1312 str.as_str().into()
1313 }
1314}
1315
1316impl<'a> From<&'a FastStr> for &'a str {
1317 #[inline]
1318 fn from(str: &'a FastStr) -> Self {
1319 str.as_str()
1320 }
1321}
1322
1323#[cfg(target_arch = "wasm32")]
1324impl From<js_sys::JsString> for FastStr {
1325 #[inline]
1326 fn from(str: js_sys::JsString) -> Self {
1327 Self::from_string(String::from(str))
1328 }
1329}
1330
1331#[cfg(target_arch = "wasm32")]
1332impl From<&js_sys::JsString> for FastStr {
1333 #[inline]
1334 fn from(str: &js_sys::JsString) -> Self {
1335 Self::from_string(String::from(str))
1336 }
1337}
1338
1339#[cfg(target_arch = "wasm32")]
1340impl From<FastStr> for js_sys::JsString {
1341 #[inline]
1342 fn from(str: FastStr) -> Self {
1343 js_sys::JsString::from(str.as_str())
1344 }
1345}
1346
1347#[cfg(target_arch = "wasm32")]
1348impl From<&FastStr> for js_sys::JsString {
1349 #[inline]
1350 fn from(str: &FastStr) -> Self {
1351 js_sys::JsString::from(str.as_str())
1352 }
1353}
1354
1355#[cfg(target_arch = "wasm32")]
1356impl From<FastStr> for wasm_bindgen::JsValue {
1357 #[inline]
1358 fn from(str: FastStr) -> Self {
1359 wasm_bindgen::JsValue::from_str(str.as_str())
1360 }
1361}
1362
1363#[cfg(target_arch = "wasm32")]
1364impl From<&FastStr> for wasm_bindgen::JsValue {
1365 #[inline]
1366 fn from(str: &FastStr) -> Self {
1367 wasm_bindgen::JsValue::from_str(str.as_str())
1368 }
1369}
1370
1371impl<A> FromIterator<A> for FastStr
1372where
1373 String: FromIterator<A>,
1374{
1375 #[inline]
1376 fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
1377 Self::from_string(String::from_iter(iter))
1378 }
1379}
1380
1381impl FromIterator<FastStr> for FastStr {
1382 fn from_iter<T: IntoIterator<Item = FastStr>>(iter: T) -> Self {
1383 let mut buf = String::new();
1384 for s in iter.into_iter() {
1385 buf += s.borrow();
1386 }
1387 Self::from(buf)
1388 }
1389}
1390
1391impl<'a> FromIterator<&'a FastStr> for FastStr {
1392 fn from_iter<T: IntoIterator<Item = &'a FastStr>>(iter: T) -> Self {
1393 Self::from_string(String::from_iter(iter.into_iter().map(|s| s.as_str())))
1394 }
1395}
1396
1397impl Add<&str> for FastStr {
1398 type Output = FastStr;
1399
1400 #[inline]
1401 fn add(self, rhs: &str) -> Self::Output {
1402 Self::from_string(String::from(self) + rhs)
1403 }
1404}
1405
1406impl Add<&FastStr> for FastStr {
1407 type Output = FastStr;
1408
1409 #[inline]
1410 fn add(self, rhs: &FastStr) -> Self::Output {
1411 Self::from_string(String::from(self) + rhs.as_str())
1412 }
1413}
1414
1415impl Add<FastStr> for FastStr {
1416 type Output = FastStr;
1417
1418 #[inline]
1419 fn add(self, rhs: FastStr) -> Self::Output {
1420 Self::from_string(String::from(self) + rhs.as_str())
1421 }
1422}
1423
1424impl Add<String> for FastStr {
1425 type Output = FastStr;
1426
1427 #[inline]
1428 fn add(self, rhs: String) -> Self::Output {
1429 Self::from_string(String::from(self) + rhs.as_str())
1430 }
1431}
1432
1433impl Add<&String> for FastStr {
1434 type Output = FastStr;
1435
1436 #[inline]
1437 fn add(self, rhs: &String) -> Self::Output {
1438 Self::from_string(String::from(self) + rhs.as_str())
1439 }
1440}
1441
1442#[cfg(target_arch = "wasm32")]
1443impl wasm_bindgen::describe::WasmDescribe for FastStr {
1444 #[inline]
1445 fn describe() {
1446 <String as wasm_bindgen::describe::WasmDescribe>::describe()
1447 }
1448}
1449
1450#[cfg(target_arch = "wasm32")]
1451impl wasm_bindgen::convert::FromWasmAbi for FastStr {
1452 type Abi = <String as wasm_bindgen::convert::FromWasmAbi>::Abi;
1453
1454 #[inline]
1455 unsafe fn from_abi(js: Self::Abi) -> Self {
1456 Self::from(<String as wasm_bindgen::convert::FromWasmAbi>::from_abi(js))
1457 }
1458}
1459
1460#[cfg(target_arch = "wasm32")]
1461impl wasm_bindgen::convert::IntoWasmAbi for FastStr {
1462 type Abi = <String as wasm_bindgen::convert::IntoWasmAbi>::Abi;
1463
1464 #[inline]
1465 fn into_abi(self) -> Self::Abi {
1466 <String as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.into_string())
1467 }
1468}
1469
1470#[cfg(target_arch = "wasm32")]
1471impl<'a> wasm_bindgen::convert::IntoWasmAbi for &'a FastStr {
1472 type Abi = <&'a str as wasm_bindgen::convert::IntoWasmAbi>::Abi;
1473
1474 #[inline]
1475 fn into_abi(self) -> Self::Abi {
1476 <&'a str as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.as_str())
1477 }
1478}
1479
1480#[cfg(target_arch = "wasm32")]
1481impl wasm_bindgen::convert::OptionFromWasmAbi for FastStr {
1482 #[inline]
1483 fn is_none(abi: &Self::Abi) -> bool {
1484 <String as wasm_bindgen::convert::OptionFromWasmAbi>::is_none(abi)
1485 }
1486}
1487
1488#[cfg(target_arch = "wasm32")]
1489impl wasm_bindgen::convert::OptionIntoWasmAbi for FastStr {
1490 #[inline]
1491 fn none() -> Self::Abi {
1492 <String as wasm_bindgen::convert::OptionIntoWasmAbi>::none()
1493 }
1494}
1495
1496#[cfg(feature = "actix-web")]
1497impl actix_web::Responder for FastStr {
1498 type Body = <String as actix_web::Responder>::Body;
1499
1500 #[inline]
1501 fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
1502 <String as actix_web::Responder>::respond_to(self.into(), req)
1503 }
1504}
1505
1506#[cfg(feature = "actix-web")]
1507impl actix_web::Responder for &FastStr {
1508 type Body = <String as actix_web::Responder>::Body;
1509
1510 #[inline]
1511 fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
1512 <String as actix_web::Responder>::respond_to(self.into(), req)
1513 }
1514}
1515
1516#[cfg(feature = "arbitrary")]
1517impl<'a> arbitrary::Arbitrary<'a> for FastStr {
1518 #[inline]
1519 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1520 <String as arbitrary::Arbitrary<'a>>::arbitrary(u).map(Self::from)
1521 }
1522
1523 #[inline]
1524 fn arbitrary_take_rest(u: arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1525 <String as arbitrary::Arbitrary<'a>>::arbitrary_take_rest(u).map(Self::from)
1526 }
1527
1528 #[inline]
1529 fn size_hint(depth: usize) -> (usize, Option<usize>) {
1530 <String as arbitrary::Arbitrary<'a>>::size_hint(depth)
1531 }
1532}
1533
1534#[cfg(feature = "diffus")]
1535impl diffus::Same for FastStr {
1536 fn same(&self, other: &Self) -> bool {
1537 self == other
1538 }
1539}
1540
1541#[cfg(feature = "diffus")]
1542impl<'a> diffus::Diffable<'a> for FastStr {
1543 type Diff = (&'a Self, &'a Self);
1544
1545 fn diff(&'a self, other: &'a Self) -> diffus::edit::Edit<'a, Self> {
1546 if self == other {
1547 diffus::edit::Edit::Copy(self)
1548 } else {
1549 diffus::edit::Edit::Change((self, other))
1550 }
1551 }
1552}
1553
1554impl<'a> Pattern<'a> for &'a FastStr {
1555 type Searcher = <&'a str as Pattern<'a>>::Searcher;
1556
1557 fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
1558 <&'a str as Pattern<'a>>::into_searcher(self.as_str(), haystack)
1559 }
1560}
1561
1562pub struct FastStrSearch<'a, 'b> {
1563 _str: Box<FastStr>,
1564 searcher: StrSearcher<'a, 'b>,
1565}
1566
1567unsafe impl<'a, 'b> Searcher<'a> for FastStrSearch<'a, 'b> {
1568 #[inline]
1569 fn haystack(&self) -> &'a str {
1570 self.searcher.haystack()
1571 }
1572
1573 #[inline]
1574 fn next(&mut self) -> SearchStep {
1575 self.searcher.next()
1576 }
1577}
1578
1579impl<'a> Pattern<'a> for FastStr {
1580 type Searcher = FastStrSearch<'a, 'a>;
1581
1582 fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
1583 let _str = Box::new(self);
1584 let searcher = <&'a str as Pattern<'a>>::into_searcher(
1585 unsafe { &*std::ptr::addr_of!(*_str.as_str()) },
1586 haystack,
1587 );
1588 FastStrSearch { _str, searcher }
1589 }
1590}