pattern_3/strings/
func.rs1use needle::*;
2use haystack::Span;
3use std::ops::Range;
4
5#[derive(Copy, Clone, Debug)]
6pub struct MultiCharEq<'p>(&'p [char]);
7
8impl<'p> FnOnce<(char,)> for MultiCharEq<'p> {
9 type Output = bool;
10 #[inline]
11 extern "rust-call" fn call_once(self, args: (char,)) -> bool {
12 self.call(args)
13 }
14}
15
16impl<'p> FnMut<(char,)> for MultiCharEq<'p> {
17 #[inline]
18 extern "rust-call" fn call_mut(&mut self, args: (char,)) -> bool {
19 self.call(args)
20 }
21}
22
23impl<'p> Fn<(char,)> for MultiCharEq<'p> {
24 #[inline]
25 extern "rust-call" fn call(&self, (c,): (char,)) -> bool {
26 self.0.iter().any(|ch| *ch == c)
27 }
28}
29
30pub struct MultiCharSearcher<F> {
31 predicate: F,
32}
33
34unsafe impl<F: FnMut(char) -> bool> Searcher<str> for MultiCharSearcher<F> {
35 #[inline]
36 fn search(&mut self, span: Span<&str>) -> Option<Range<usize>> {
37 let (hay, range) = span.into_parts();
38 let st = range.start;
39 let h = &hay[range];
40 let mut chars = h.chars();
41 let c = chars.find(|c| (self.predicate)(*c))?;
42 let end = chars.as_str().as_ptr();
43 let end = unsafe { end.offset_from(h.as_ptr()) as usize } + st;
44 Some((end - c.len_utf8())..end)
45 }
46}
47
48unsafe impl<F: FnMut(char) -> bool> Consumer<str> for MultiCharSearcher<F> {
49 #[inline]
50 fn consume(&mut self, hay: Span<&str>) -> Option<usize> {
51 let (hay, range) = hay.into_parts();
52 let start = range.start;
53 if start == range.end {
54 return None;
55 }
56 let c = unsafe { hay.get_unchecked(start..) }.chars().next().unwrap();
57 if (self.predicate)(c) {
58 Some(start + c.len_utf8())
59 } else {
60 None
61 }
62 }
63
64 #[inline]
65 fn trim_start(&mut self, hay: &str) -> usize {
66 let mut chars = hay.chars();
67 let unconsume_amount = chars
68 .find_map(|c| if !(self.predicate)(c) { Some(c.len_utf8()) } else { None })
69 .unwrap_or(0);
70 let consumed = unsafe { chars.as_str().as_ptr().offset_from(hay.as_ptr()) as usize };
71 consumed.wrapping_sub(unconsume_amount)
72 }
73}
74
75unsafe impl<F: FnMut(char) -> bool> ReverseSearcher<str> for MultiCharSearcher<F> {
76 #[inline]
77 fn rsearch(&mut self, span: Span<&str>) -> Option<Range<usize>> {
78 let (hay, range) = span.into_parts();
79 let st = range.start;
80 let h = &hay[range];
81 let mut chars = h.chars();
82 let c = chars.rfind(|c| (self.predicate)(*c))?;
83 let start = chars.as_str().len() + st;
84 Some(start..(start + c.len_utf8()))
85 }
86}
87
88unsafe impl<F: FnMut(char) -> bool> ReverseConsumer<str> for MultiCharSearcher<F> {
89 #[inline]
90 fn rconsume(&mut self, hay: Span<&str>) -> Option<usize> {
91 let (hay, range) = hay.into_parts();
92 let end = range.end;
93 if range.start == end {
94 return None;
95 }
96 let c = unsafe { hay.get_unchecked(..end) }.chars().next_back().unwrap();
97 if (self.predicate)(c) {
98 Some(end - c.len_utf8())
99 } else {
100 None
101 }
102 }
103
104 #[inline]
105 fn trim_end(&mut self, hay: &str) -> usize {
106 let mut chars = hay.chars();
109 let unconsume_amount = chars
110 .by_ref()
111 .rev() .find(|c| !(self.predicate)(*c))
113 .map_or(0, |c| c.len_utf8());
114 chars.as_str().len() + unconsume_amount
115 }
116}
117
118unsafe impl<F: FnMut(char) -> bool> DoubleEndedSearcher<str> for MultiCharSearcher<F> {}
119unsafe impl<F: FnMut(char) -> bool> DoubleEndedConsumer<str> for MultiCharSearcher<F> {}
120
121macro_rules! impl_needle {
122 ($ty:ty) => {
123 impl<'h, F: FnMut(char) -> bool> Needle<$ty> for F {
124 type Searcher = MultiCharSearcher<F>;
125 type Consumer = MultiCharSearcher<F>;
126
127 #[inline]
128 fn into_searcher(self) -> Self::Searcher {
129 MultiCharSearcher { predicate: self }
130 }
131
132 #[inline]
133 fn into_consumer(self) -> Self::Consumer {
134 MultiCharSearcher { predicate: self }
135 }
136 }
137
138 impl<'h, 'p> Needle<$ty> for &'p [char] {
139 type Searcher = MultiCharSearcher<MultiCharEq<'p>>;
140 type Consumer = MultiCharSearcher<MultiCharEq<'p>>;
141
142 #[inline]
143 fn into_searcher(self) -> Self::Searcher {
144 MultiCharSearcher { predicate: MultiCharEq(self) }
145 }
146
147 #[inline]
148 fn into_consumer(self) -> Self::Consumer {
149 MultiCharSearcher { predicate: MultiCharEq(self) }
150 }
151 }
152 }
153}
154
155impl_needle!(&'h str);
156impl_needle!(&'h mut str);