1use {
4 crate::{
5 tuple::{first, map_second, Tuple},
6 Input, Parser, ParsingError,
7 },
8 core::{ops::Not, convert::Infallible},
9};
10
11pub trait Pattern {
20 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I>;
27
28 #[expect(
34 clippy::unwrap_used,
35 reason = "this will only panic if the pattern does"
36 )]
37 fn immediate_matches<I: Input>(&self, input: I) -> (I, I) {
38 let mut rest = Some(input.clone());
39 let rest_ptr = loop {
40 match self.immediate_match(rest.take().unwrap()) {
41 Ok((x, _)) => rest = Some(x),
42 Err(x) => break x.as_ptr(),
43 }
44 };
45 let input_ptr = input.as_ptr();
46 input.split_at(rest_ptr as usize - input_ptr as usize).rev()
47 }
48
49 #[expect(
53 clippy::unwrap_used,
54 reason = "this will only panic if the pattern does"
55 )]
56 fn immediate_matches_counted<I: Input>(&self, input: I) -> (I, (I, usize)) {
57 let mut rest = Some(input.clone());
58 let mut n = 0;
59 let rest_ptr = loop {
60 match self.immediate_match(rest.take().unwrap()) {
61 Ok((x, _)) => {
62 rest = Some(x);
63 n += 1;
64 }
65 Err(x) => break x.as_ptr(),
66 }
67 };
68 let input_ptr = input.as_ptr();
69 input
70 .split_at(rest_ptr as usize - input_ptr as usize)
71 .rev()
72 .map_second(|s| (s, n))
73 }
74
75 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I>;
83
84 #[expect(
89 clippy::unwrap_used,
90 reason = "this will only panic if the pattern does"
91 )]
92 fn trailing_matches_counted<I: Input>(&self, input: I) -> (I, usize) {
93 let mut rest = Some(input);
94 let mut n = 0;
95 loop {
96 match self.trailing_match(rest.take().unwrap()) {
97 Ok((before, _)) => {
98 rest = Some(before);
99 n += 1;
100 }
101 Err(rest) => break (rest, n),
102 }
103 }
104 }
105
106 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I>;
113
114 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I>;
121
122 fn by_ref(&self) -> impl Pattern + Copy {
126 #[repr(transparent)]
127 struct Ref<'this, T: ?Sized>(&'this T);
128
129 impl<T: ?Sized> Clone for Ref<'_, T> {
130 fn clone(&self) -> Self {
131 *self
132 }
133 }
134
135 impl<T: ?Sized> Copy for Ref<'_, T> {}
136
137 impl<T: Pattern + ?Sized> Pattern for Ref<'_, T> {
138 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
139 T::immediate_match(self.0, input)
140 }
141
142 fn immediate_matches<I: Input>(&self, input: I) -> (I, I) {
143 T::immediate_matches(self.0, input)
144 }
145
146 fn immediate_matches_counted<I: Input>(&self, input: I) -> (I, (I, usize)) {
147 T::immediate_matches_counted(self.0, input)
148 }
149
150 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
151 T::trailing_match(self.0, input)
152 }
153
154 fn trailing_matches_counted<I: Input>(&self, input: I) -> (I, usize) {
155 T::trailing_matches_counted(self.0, input)
156 }
157
158 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
159 T::first_match(self.0, input)
160 }
161
162 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
163 T::first_match_ex(self.0, input)
164 }
165 }
166
167 Ref(self)
168 }
169
170 fn or<Other: Pattern>(self, other: Other) -> Union<Self, Other>
175 where
176 Self: Sized,
177 {
178 Union(self, other)
179 }
180}
181
182impl<F: Fn(char) -> bool> Pattern for F {
183 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
184 match input.chars().next().filter(|c| self(*c)) {
185 Some(c) => Ok(input.split_at(c.len_utf8()).rev()),
186 None => Err(input),
187 }
188 }
189
190 fn immediate_matches<I: Input>(&self, input: I) -> (I, I) {
191 let mid = input.find(|c| !self(c)).unwrap_or(input.len());
192 input.split_at(mid).rev()
193 }
194
195 fn immediate_matches_counted<I: Input>(&self, input: I) -> (I, (I, usize)) {
196 let mut char_index = 0;
197 let byte_index = input
198 .char_indices()
199 .inspect(|_| char_index += 1)
200 .find_map(|(bi, c)| self(c).not().then_some(bi))
201 .inspect(|_| char_index -= 1)
202 .unwrap_or(input.len());
203 input
204 .split_at(byte_index)
205 .rev()
206 .map_second(|s| (s, char_index))
207 }
208
209 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
210 match input.strip_suffix(self).map(str::len) {
211 Some(len) => Ok(input.split_at(len)),
212 None => Err(input),
213 }
214 }
215
216 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
217 match input.char_indices().find(|(_, c)| self(*c)) {
218 Some((at, ch)) => {
219 let (before, after) = input.split_at(at);
220 let r#match = after.clone().before(ch.len_utf8());
221 Ok((after, (before, r#match)))
222 }
223 None => Err(input),
224 }
225 }
226
227 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
228 match input.char_indices().find(|(_, c)| self(*c)) {
229 Some((at, ch)) => {
230 let (before, after) = input.split_at(at);
231 let (r#match, after) = after.split_at(ch.len_utf8());
232 Ok((after, (before, r#match)))
233 }
234 None => Err(input),
235 }
236 }
237}
238
239impl<const N: usize> Pattern for [char; N] {
242 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
244 match input.strip_prefix(self) {
245 Some(rest) => {
246 let matched_pat_len = input.len() - rest.len();
247 Ok(input.split_at(matched_pat_len).rev())
248 }
249 None => Err(input),
250 }
251 }
252
253 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
254 match input.strip_suffix(self) {
255 Some(rest) => {
256 let rest_len = rest.len();
257 Ok(input.split_at(rest_len))
258 }
259 None => Err(input),
260 }
261 }
262
263 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
264 match input.find(self) {
265 Some(at) => {
266 let (prev, match_and_rest) = input.split_at(at);
267 let matched_pat_len = match_and_rest.chars().next().map_or(0, char::len_utf8);
268 let r#match = match_and_rest.clone().before(matched_pat_len);
269 Ok((match_and_rest, (prev, r#match)))
270 }
271 None => Err(input),
272 }
273 }
274
275 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
276 match input.find(self) {
277 Some(at) => {
278 let (prev, match_and_rest) = input.split_at(at);
279 let matched_pat_len = match_and_rest.chars().next().map_or(0, char::len_utf8);
280 let (r#match, rest) = match_and_rest.split_at(matched_pat_len);
281 Ok((rest, (prev, r#match)))
282 }
283 None => Err(input),
284 }
285 }
286}
287
288impl Pattern for &str {
289 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
290 if input.starts_with(*self) {
291 Ok(input.split_at(self.len()).rev())
292 } else {
293 Err(input)
294 }
295 }
296
297 fn immediate_matches<I: Input>(&self, input: I) -> (I, I) {
298 let rest_len = input.trim_start_matches(self).len();
299 let input_len = input.len();
300 input.split_at(input_len - rest_len).rev()
301 }
302
303 fn immediate_matches_counted<I: Input>(&self, input: I) -> (I, (I, usize)) {
304 self.immediate_matches(input)
305 .map_second(|s| (s.len().checked_div(self.len()).unwrap_or(0), s).rev())
306 }
307
308 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
309 if input.ends_with(self) {
310 let mid = input.len() - self.len();
311 Ok(input.split_at(mid))
312 } else {
313 Err(input)
314 }
315 }
316
317 fn trailing_matches_counted<I: Input>(&self, input: I) -> (I, usize) {
318 let trimmed_len = input.trim_end_matches(self).len();
319 let input_len = input.len();
320 (
321 input.before(trimmed_len),
322 (input_len - trimmed_len) / self.len(),
323 )
324 }
325
326 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
327 match input.find(*self) {
328 Some(at) => {
329 let (before, after) = input.split_at(at);
330 let r#match = after.clone().before(self.len());
331 Ok((after, (before, r#match)))
332 }
333 None => Err(input),
334 }
335 }
336
337 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
338 match input.find(*self) {
339 Some(at) => {
340 let (before, after) = input.split_at(at);
341 let (r#match, after) = after.split_at(self.len());
342 Ok((after, (before, r#match)))
343 }
344 None => Err(input),
345 }
346 }
347}
348
349impl Pattern for char {
350 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
351 if input.starts_with(*self) {
352 Ok(input.split_at(self.len_utf8()).rev())
353 } else {
354 Err(input)
355 }
356 }
357
358 fn immediate_matches<I: Input>(&self, input: I) -> (I, I) {
359 let rest_len = input.trim_start_matches(*self).len();
360 let input_len = input.len();
361 input.split_at(input_len - rest_len).rev()
362 }
363
364 fn immediate_matches_counted<I: Input>(&self, input: I) -> (I, (I, usize)) {
365 self.immediate_matches(input)
366 .map_second(|s| (s.len() / self.len_utf8(), s).rev())
367 }
368
369 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
370 if input.ends_with(*self) {
371 let mid = input.len() - self.len_utf8();
372 Ok(input.split_at(mid))
373 } else {
374 Err(input)
375 }
376 }
377
378 fn trailing_matches_counted<I: Input>(&self, input: I) -> (I, usize) {
379 let trimmed_len = input.trim_end_matches(*self).len();
380 let input_len = input.len();
381 (
382 input.before(trimmed_len),
383 (input_len - trimmed_len) / self.len_utf8(),
384 )
385 }
386
387 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
388 match input.find(*self) {
389 Some(at) => {
390 let (before, after) = input.split_at(at);
391 let r#match = after.clone().before(self.len_utf8());
392 Ok((after, (before, r#match)))
393 }
394 None => Err(input),
395 }
396 }
397
398 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
399 match input.find(*self) {
400 Some(at) => {
401 let (before, after) = input.split_at(at);
402 let (r#match, after) = after.split_at(self.len_utf8());
403 Ok((after, (before, r#match)))
404 }
405 None => Err(input),
406 }
407 }
408}
409
410pub struct NotEscaped<Prefix: Pattern, Inner: Pattern>(pub Prefix, pub Inner);
417
418impl<Prefix: Pattern, Inner: Pattern> Pattern for NotEscaped<Prefix, Inner> {
419 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
420 self.1.immediate_match(input)
421 }
422
423 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
424 let (rest, r#match) = self.1.trailing_match(input.clone())?;
425 let (rest, n_prefixes) = self.0.trailing_matches_counted(rest);
426 (n_prefixes % 2 == 0)
427 .then_some((rest, r#match))
428 .ok_or(input)
429 }
430
431 fn trailing_matches_counted<I: Input>(&self, input: I) -> (I, usize) {
432 let (rest, n) = self.1.trailing_matches_counted(input);
433 if n == 0 {
434 return (rest, 0);
435 }
436 let no_1st_prefix = match self.0.trailing_match(rest.clone()) {
437 Ok((x, _)) => x,
438 Err(rest) => return (rest, n),
439 };
440 let (_, n_prefixes_minus_one) = self.0.trailing_matches_counted(no_1st_prefix.clone());
441 if n_prefixes_minus_one % 2 != 0 {
442 (rest, n)
443 } else {
444 (no_1st_prefix, n - 1)
445 }
446 }
447
448 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
449 let mut rest = input.clone();
450 while !rest.is_empty() {
451 let (before, r#match);
452 (rest, (before, r#match)) = self.1.first_match(rest)?;
453 let before = match self.0.trailing_match(before) {
454 Ok((x, _)) => x,
455 Err(before) => return Ok((rest, (before, r#match))),
456 };
457 let (before, n_prefixes_minus_one) = self.0.trailing_matches_counted(before);
458 if n_prefixes_minus_one % 2 != 0 {
459 return Ok((rest, (before, r#match)));
460 }
461 }
462 Err(input)
463 }
464
465 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
466 let mut rest = input.clone();
467 loop {
468 let (before, r#match);
469 (rest, (before, r#match)) = self.1.first_match_ex(rest)?;
470 let Ok((before, _)) = self.0.trailing_match(before) else {
471 let index = r#match.as_ptr() as usize - input.as_ptr() as usize;
472 let before = input.before(index);
473 return Ok((rest, (before, r#match)));
474 };
475 let (_, n_prefixes_minus_one) = self.0.trailing_matches_counted(before);
476 if n_prefixes_minus_one % 2 != 0 {
477 let index = r#match.as_ptr() as usize - input.as_ptr() as usize;
478 let before = input.before(index);
479 return Ok((rest, (before, r#match)));
480 }
481 }
482 }
483}
484
485pub struct AnyChar;
487
488impl Pattern for AnyChar {
489 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
490 match input.chars().next() {
491 Some(ch) => Ok(input.split_at(ch.len_utf8()).rev()),
492 None => Err(input),
493 }
494 }
495
496 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
497 match input.chars().next_back() {
498 Some(ch) => Ok(input.split_at(ch.len_utf8())),
499 None => Err(input),
500 }
501 }
502
503 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
504 Ok((input.clone(), (I::default(), input)))
505 }
506
507 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
508 Ok((I::default(), (I::default(), input)))
509 }
510}
511
512pub struct Union<P1: Pattern, P2: Pattern>(pub P1, pub P2);
522
523impl<P1: Pattern, P2: Pattern> Pattern for Union<P1, P2> {
524 fn immediate_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
525 self.0
526 .immediate_match(input)
527 .or_else(|input| self.1.immediate_match(input))
528 }
529
530 fn trailing_match<I: Input>(&self, input: I) -> Result<(I, I), I> {
531 self.0
532 .trailing_match(input)
533 .or_else(|input| self.1.trailing_match(input))
534 }
535
536 fn first_match<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
537 self.0
538 .first_match(input)
539 .or_else(|input| self.1.first_match(input))
540 }
541
542 fn first_match_ex<I: Input>(&self, input: I) -> Result<(I, (I, I)), I> {
543 self.0
544 .first_match_ex(input)
545 .or_else(|input| self.1.first_match_ex(input))
546 }
547}
548
549pub fn parse<In: Input, Reason>(pat: impl Pattern) -> impl Parser<In, In, Reason> {
555 move |input| {
556 pat.immediate_match(input)
557 .map_err(ParsingError::new_recoverable)
558 }
559}
560
561pub fn parse_while<In: Input, Reason>(pat: impl Pattern) -> impl Parser<In, In, Reason> {
568 move |input| Ok(pat.immediate_matches(input))
569}
570
571pub fn parse_until<In: Input, Reason>(pat: impl Pattern) -> impl Parser<In, In, Reason> {
580 move |input| {
581 Ok({
582 pat.first_match(input)
583 .map_or_else(|input| (In::default(), input), map_second(first))
584 })
585 }
586}
587
588pub fn parse_until_ex<In: Input, Reason>(pat: impl Pattern) -> impl Parser<In, In, Reason> {
594 move |input| {
595 pat.first_match_ex(input)
596 .map(map_second(first))
597 .map_err(ParsingError::new_recoverable)
598 }
599}
600
601#[expect(
619 clippy::missing_panics_doc,
620 clippy::unwrap_used,
621 reason = "Panics only if the pattern does"
622)]
623pub fn parse_group<In: Input>(open: impl Pattern, close: impl Pattern) -> impl Parser<In, In, ()> {
624 move |input| {
625 let (open, close) = (open.by_ref(), close.by_ref());
626 let (mut rest, _) = parse(open)(input.clone())?;
627 let after_1st_open = rest.clone();
628 let mut depth = 0usize;
629 loop {
630 let mut group;
631 match parse_until_ex::<_, Infallible>(close)(rest) {
632 Ok(x) => (rest, group) = x,
633 Err(_) => break Err(ParsingError::new(input, ())),
634 }
635 let mut after_open = Some(group);
636 group = loop {
637 match parse_until_ex::<_, Infallible>(open)(after_open.take().unwrap()) {
638 Ok((x, _)) => {
639 depth += 1;
640 after_open = Some(x);
641 }
642 Err(x) => break x.rest,
643 };
644 };
645 if depth == 0 {
646 let len = group.as_ptr() as usize + group.len() - after_1st_open.as_ptr() as usize;
647 break Ok((rest, after_1st_open.before(len)));
648 }
649 depth -= 1;
650 }
651 }
652}
653
654#[test]
655fn char_pat() {
656 assert_eq!(
657 parse_until_ex::<_, Infallible>('"')
658 .parse(r#"this is what they call a \"test\", right?" - he said"#),
659 Ok((
660 r#"test\", right?" - he said"#,
661 r"this is what they call a \"
662 )),
663 );
664}
665
666#[test]
667fn not_escaped_pat() {
668 assert_eq!(
669 parse_until_ex::<_, Infallible>(NotEscaped('\\', '"'))
670 .parse(r#"this is what they call a \"test\", right?" - he said"#),
671 Ok((" - he said", r#"this is what they call a \"test\", right?"#)),
672 );
673}
674
675#[test]
676fn str_pat() {
677 assert_eq!(parse::<_, Infallible>("abc")("abcdef"), Ok(("def", "abc")));
678}
679
680#[test]
681fn array_pat() {
682 assert_eq!(
683 parse_until_ex::<_, Infallible>([';', '\''])("abc;def'xyz"),
684 Ok(("def'xyz", "abc"))
685 );
686}
687
688#[test]
689fn union_pat() {
690 let src = "abc;def'xyz";
691 assert_eq!(
692 parse_until_ex::<_, Infallible>(';'.or('\''))(src),
693 parse_until_ex([';', '\''])(src)
694 );
695}