cheetah_string/cheetah_string/
pattern.rs1use alloc::string::String;
2use core::str;
3
4mod private {
6 use alloc::string::String;
7
8 pub trait Sealed {}
9 impl Sealed for char {}
10 impl Sealed for &str {}
11 impl Sealed for &String {}
12
13 pub trait SplitSealed {}
14 impl SplitSealed for char {}
15 impl SplitSealed for &str {}
16}
17
18pub trait StrPattern: private::Sealed {
20 #[doc(hidden)]
21 fn as_str_pattern(&self) -> StrPatternImpl<'_>;
22}
23
24#[doc(hidden)]
25pub enum StrPatternImpl<'a> {
26 Char(char),
27 Str(&'a str),
28}
29
30impl StrPattern for char {
31 #[inline]
32 fn as_str_pattern(&self) -> StrPatternImpl<'_> {
33 StrPatternImpl::Char(*self)
34 }
35}
36
37impl StrPattern for &str {
38 #[inline]
39 fn as_str_pattern(&self) -> StrPatternImpl<'_> {
40 StrPatternImpl::Str(self)
41 }
42}
43
44impl StrPattern for &String {
45 #[inline]
46 fn as_str_pattern(&self) -> StrPatternImpl<'_> {
47 StrPatternImpl::Str(self.as_str())
48 }
49}
50
51pub trait SplitPattern<'a>: private::SplitSealed {
53 #[doc(hidden)]
54 fn split_str(self, s: &'a str) -> SplitWrapper<'a>;
55}
56
57impl SplitPattern<'_> for char {
58 fn split_str(self, s: &str) -> SplitWrapper<'_> {
59 SplitWrapper::Char(s.split(self))
60 }
61}
62
63impl<'a> SplitPattern<'a> for &'a str {
64 fn split_str(self, s: &'a str) -> SplitWrapper<'a> {
65 let inner = match single_char_pattern(self) {
66 Some(ch) => SplitStrInner::Char(s.split(ch)),
67 None => SplitStrInner::Str(s.split(self)),
68 };
69
70 SplitWrapper::Str(SplitStr(inner))
71 }
72}
73
74pub struct SplitStr<'a>(SplitStrInner<'a>);
76
77enum SplitStrInner<'a> {
78 Str(str::Split<'a, &'a str>),
79 Char(str::Split<'a, char>),
80}
81
82#[inline]
83fn single_char_pattern(pattern: &str) -> Option<char> {
84 let mut chars = pattern.chars();
85 let ch = chars.next()?;
86
87 if chars.next().is_none() {
88 Some(ch)
89 } else {
90 None
91 }
92}
93
94impl<'a> Iterator for SplitStr<'a> {
95 type Item = &'a str;
96
97 fn next(&mut self) -> Option<Self::Item> {
98 match &mut self.0 {
99 SplitStrInner::Str(iter) => iter.next(),
100 SplitStrInner::Char(iter) => iter.next(),
101 }
102 }
103}
104
105pub enum SplitWrapper<'a> {
107 #[doc(hidden)]
108 Char(str::Split<'a, char>),
109 #[doc(hidden)]
110 Str(SplitStr<'a>),
111}
112
113impl<'a> Iterator for SplitWrapper<'a> {
114 type Item = &'a str;
115
116 fn next(&mut self) -> Option<Self::Item> {
117 match self {
118 SplitWrapper::Char(iter) => iter.next(),
119 SplitWrapper::Str(iter) => iter.next(),
120 }
121 }
122}
123
124impl<'a> DoubleEndedIterator for SplitWrapper<'a> {
125 fn next_back(&mut self) -> Option<Self::Item> {
126 match self {
127 SplitWrapper::Char(iter) => iter.next_back(),
128 SplitWrapper::Str(_) => {
129 panic!("split with string pattern does not support reverse iteration")
131 }
132 }
133 }
134}