1pub mod prelude {
71 pub use crate::{SplitEvery, SplitEveryImpl, SplitEveryIterImpl};
72}
73
74pub trait SplitEveryImpl: Sized {
75 fn split_every_n_times(self, pat: Self, n: usize) -> SplitEvery<Self, Self> {
76 SplitEvery {
77 input: self,
78 pat,
79 n,
80 ind: 0,
81 }
82 }
83}
84
85impl SplitEveryImpl for &str {}
86impl SplitEveryImpl for String {}
87impl SplitEveryImpl for std::string::Drain<'_> {}
88impl<T: Clone + PartialEq> SplitEveryImpl for Vec<T> {}
89impl<T: Clone + PartialEq> SplitEveryImpl for &[T] {}
90
91pub trait SplitEveryIterImpl<'a, T: Clone + PartialEq>: Iterator<Item = T> + Sized + 'a {
92 fn split_every_n_times(
93 mut self,
94 pat: T,
95 n: usize,
96 ) -> SplitEvery<Box<dyn FnMut() -> Option<T> + 'a>, T> {
97 SplitEvery::n_times_from_fn(Box::new(move || self.next()), pat, n)
98 }
99}
100
101impl<'a, T: Clone + PartialEq, U: Iterator<Item = T> + Sized + 'a> SplitEveryIterImpl<'a, T> for U {}
102
103pub struct SplitEvery<Input, Pattern> {
104 input: Input,
105 pat: Pattern,
106 n: usize,
107 ind: usize,
108}
109
110impl<Input: FnMut() -> Option<Pattern>, Pattern: PartialEq> SplitEvery<Input, Pattern> {
111 pub fn n_times_from_fn(input: Input, pat: Pattern, n: usize) -> SplitEvery<Input, Pattern> {
112 SplitEvery {
113 input,
114 pat,
115 n,
116 ind: 0,
117 }
118 }
119}
120
121impl<Input: FnMut() -> Option<Pattern>, Pattern: PartialEq> Iterator
122 for SplitEvery<Input, Pattern>
123{
124 type Item = Vec<Pattern>;
125
126 fn next(&mut self) -> Option<Self::Item> {
127 if self.n == 0 {
128 let out: Vec<Pattern> = std::iter::repeat_with(|| (self.input)())
129 .take_while(Option::is_some)
130 .flatten()
131 .collect();
132 if out.is_empty() {
133 return None;
134 }
135 return Some(out);
136 }
137 let mut out: Vec<Pattern> = Vec::with_capacity(5);
138 'main: for ind in 0..self.n {
139 while let Some(val) = (self.input)() {
140 if val == self.pat {
141 if ind == unsafe { self.n.unchecked_sub(1) } {
142 break 'main;
143 }
144 out.push(val);
145 continue 'main;
146 }
147 out.push(val);
148 }
149 }
150 if out.is_empty() {
151 return None;
152 }
153 Some(out)
154 }
155}
156
157impl<Pattern: AsRef<str>> Iterator for SplitEvery<&str, Pattern> {
158 type Item = String;
159
160 fn next(&mut self) -> Option<Self::Item> {
161 split_every_next_str_helper(self)
162 }
163}
164
165impl<Pattern: AsRef<str>> Iterator for SplitEvery<String, Pattern> {
166 type Item = String;
167
168 fn next(&mut self) -> Option<Self::Item> {
169 split_every_next_str_helper(self)
170 }
171}
172
173impl<Pattern: AsRef<str>> Iterator for SplitEvery<std::string::Drain<'_>, Pattern> {
174 type Item = String;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 split_every_next_str_helper(self)
178 }
179}
180
181fn split_every_next_str_helper<Input: AsRef<str>, Pattern: AsRef<str>>(
182 split_every: &mut SplitEvery<Input, Pattern>,
183) -> Option<String> {
184 let input: &str = split_every.input.as_ref();
185 if split_every.ind == input.len() {
186 return None;
187 }
188 let pat: &str = split_every.pat.as_ref();
189 let iter_haystack: &str = unsafe { input.get_unchecked(split_every.ind..) };
190 let mut len: usize = 0;
191 for ind in 0..split_every.n {
192 let haystack: &str = unsafe { iter_haystack.get_unchecked(len..) };
193 if let Some(byte_ind) = haystack.find(pat) {
194 len = unsafe { len.unchecked_add(byte_ind).unchecked_add(pat.len()) };
195 continue;
196 }
197 if ind == 0 {
198 split_every.ind = input.len();
199 return Some(haystack.to_string());
200 }
201 break;
202 }
203 split_every.ind = unsafe { split_every.ind.unchecked_add(len) };
204 Some(unsafe { iter_haystack.get_unchecked(..len.unchecked_sub(pat.len())) }.to_string())
205}
206
207impl<T: Clone + PartialEq> Iterator for SplitEvery<Vec<T>, Vec<T>> {
208 type Item = Vec<T>;
209
210 fn next(&mut self) -> Option<Self::Item> {
211 let (ind, out): (usize, Option<Vec<T>>) =
212 split_every_next_arr_helper(self, &self.input, &self.pat);
213 self.ind = ind;
214 out
215 }
216}
217
218impl<T: Clone + PartialEq> Iterator for SplitEvery<&[T], &[T]> {
219 type Item = Vec<T>;
220
221 fn next(&mut self) -> Option<Self::Item> {
222 let (ind, out): (usize, Option<Vec<T>>) =
223 split_every_next_arr_helper(self, self.input, self.pat);
224 self.ind = ind;
225 out
226 }
227}
228
229fn split_every_next_arr_helper<T, U: Clone + PartialEq>(
230 split_every: &SplitEvery<T, T>,
231 input: &[U],
232 pat: &[U],
233) -> (usize, Option<Vec<U>>) {
234 if split_every.ind == input.len() {
235 return (split_every.ind, None);
236 }
237 let iter_haystack: &[U] = unsafe { input.get_unchecked(split_every.ind..) };
238 let mut len: usize = 0;
239 for ind in 0..split_every.n {
240 if len == iter_haystack.len() {
241 break;
242 }
243 if let Some((ind, _)) = unsafe { iter_haystack.get_unchecked(len..) }
244 .windows(pat.len())
245 .enumerate()
246 .find(|(_, val)| val == &pat)
247 {
248 len = unsafe { len.unchecked_add(ind).unchecked_add(pat.len()) };
249 continue;
250 }
251 if ind == 0 {
252 return (input.len(), Some(iter_haystack.to_vec()));
253 }
254 break;
255 }
256 (
257 unsafe { split_every.ind.unchecked_add(len) },
258 Some(unsafe { iter_haystack.get_unchecked(..len.unchecked_sub(pat.len())) }.to_vec()),
259 )
260}
261
262#[test]
263fn test() {
264 let mut splitter: SplitEvery<&str, &str> = "oh oh oh oh oh".split_every_n_times(" ", 2);
265 assert_eq!(splitter.next().unwrap(), "oh oh");
266 assert_eq!(splitter.next().unwrap(), "oh oh");
267 assert_eq!(splitter.next().unwrap(), "oh");
268 assert_eq!(splitter.next(), None);
269
270 let mut splitter: SplitEvery<&str, &str> = "a a a a".split_every_n_times("b", 2);
271 assert_eq!(splitter.next().unwrap(), "a a a a");
272 assert_eq!(splitter.next(), None);
273
274 let mut splitter: SplitEvery<Box<dyn FnMut() -> Option<&'static str>>, &str> = [
275 ["This", "is", "you"],
276 ["This", "is", "me"],
277 ["This", "is", "someone"],
278 ["This", "is", "them"],
279 ]
280 .iter()
281 .flatten()
282 .copied()
283 .split_every_n_times("is", 2);
284 assert_eq!(splitter.next().unwrap(), vec!["This", "is", "you", "This"]);
285 assert_eq!(
286 splitter.next().unwrap(),
287 vec!["me", "This", "is", "someone", "This"]
288 );
289 assert_eq!(splitter.next().unwrap(), vec!["them"]);
290 assert_eq!(splitter.next(), None);
291
292 let mut iter = [
293 ["This", "is", "you"],
294 ["This", "is", "me"],
295 ["This", "is", "someone"],
296 ["This", "is", "them"],
297 ]
298 .iter()
299 .flatten()
300 .copied();
301 let mut splitter: SplitEvery<Box<dyn FnMut() -> Option<&'static str>>, &str> =
302 SplitEvery::<Box<dyn FnMut() -> Option<&'static str>>, &str>::n_times_from_fn(
303 Box::new(move || iter.next()),
304 "is",
305 2,
306 );
307 assert_eq!(splitter.next().unwrap(), vec!["This", "is", "you", "This"]);
308 assert_eq!(
309 splitter.next().unwrap(),
310 vec!["me", "This", "is", "someone", "This"]
311 );
312 assert_eq!(splitter.next().unwrap(), vec!["them"]);
313 assert_eq!(splitter.next(), None);
314
315 #[allow(clippy::type_complexity)]
316 let mut splitter: SplitEvery<&[(u8, u8)], &[(u8, u8)]> = [
317 (0, 0),
318 (0, 1),
319 (0, 0), (0, 0),
321 (0, 0), (0, 1),
323 (0, 0),
324 (0, 0), (0, 1),
326 ]
327 .split_every_n_times(&[(0, 0)], 2);
328 assert_eq!(splitter.next().unwrap(), vec![(0, 0), (0, 1)]);
329 assert_eq!(splitter.next().unwrap(), vec![(0, 0)]);
330 assert_eq!(splitter.next().unwrap(), vec![(0, 1), (0, 0)]);
331 assert_eq!(splitter.next().unwrap(), vec![(0, 1)]);
332 assert_eq!(splitter.next(), None);
333
334 let mut splitter: SplitEvery<&str, &str> =
335 "Oh hi there I don't really know what to say".split_every_n_times(" ", 3);
336 assert_eq!(splitter.next().unwrap(), "Oh hi there");
337 assert_eq!(splitter.next().unwrap(), "I don't really");
338 assert_eq!(splitter.next().unwrap(), "know what to");
339 assert_eq!(splitter.next().unwrap(), "say");
340 assert_eq!(splitter.next(), None);
341}