harper_core/patterns/
repeating_pattern.rs1use super::Pattern;
2use crate::Token;
3
4pub struct RepeatingPattern {
8 inner: Box<dyn Pattern>,
9 required_repetitions: usize,
10}
11
12impl RepeatingPattern {
13 pub fn new(pattern: Box<dyn Pattern>, required_repetitions: usize) -> Self {
14 Self {
15 inner: pattern,
16 required_repetitions,
17 }
18 }
19}
20
21impl Pattern for RepeatingPattern {
22 fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
23 let mut tok_cursor = 0;
24 let mut repetition = 0;
25
26 loop {
27 let match_len = self.inner.matches(&tokens[tok_cursor..], source);
28
29 if let Some(match_len) = match_len {
30 if match_len == 0 {
31 return Some(tok_cursor);
35 }
36
37 tok_cursor += match_len;
38 repetition += 1;
39 } else if repetition >= self.required_repetitions {
40 return Some(tok_cursor);
41 } else {
42 return None;
43 }
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50
51 use super::RepeatingPattern;
52 use crate::Document;
53 use crate::patterns::{AnyPattern, Pattern};
54
55 #[test]
56 fn matches_anything() {
57 let doc = Document::new_plain_english_curated(
58 "This matcher will match the entirety of any document!",
59 );
60 let pat = RepeatingPattern::new(Box::new(AnyPattern), 0);
61
62 assert_eq!(
63 pat.matches(doc.get_tokens(), doc.get_source()),
64 Some(doc.get_tokens().len())
65 )
66 }
67
68 #[test]
69 fn does_not_match_short() {
70 let doc = Document::new_plain_english_curated("No match");
71 let pat = RepeatingPattern::new(Box::new(AnyPattern), 4);
72
73 assert_eq!(pat.matches(doc.get_tokens(), doc.get_source()), None)
74 }
75}