1use core::{
2 fmt,
3 ops::{Bound, RangeBounds},
4};
5
6use crate::utils::default;
7
8use super::{
9 machine::{RepeatState, RepeatStyle, StackItem},
10 traits::IntoMatchString,
11 DebugPrecedence, Link, MatchString, Matcher, StringMatcherContext, StringPattern,
12};
13
14struct RepeatContinue {}
15
16pub struct Repeat<'m, M> {
17 min: u32,
18 max: u32,
19 style: RepeatStyle,
20 inner: M,
21 links: (Link<'m>, Link<'m>),
22}
23
24impl<'m, M: MatchString<'m>> Repeat<'m, M> {
25 fn get_repeat_parts(
26 &'m self,
27 cx: &mut StringMatcherContext<'m, '_>,
28 ) -> (StackItem<'m>, StackItem<'m>) {
29 let (inner, outer) = if cx.is_reversed() {
30 (self.inner.last(), self.backward_matcher())
31 } else {
32 (self.inner.first(), self.forward_matcher())
33 };
34
35 let outer = if let Some(outer) = outer {
36 StackItem::Matcher { matcher: outer }
37 } else {
38 StackItem::Accept
39 };
40
41 let inner = StackItem::Matcher { matcher: inner };
42
43 (outer, inner)
44 }
45}
46
47impl<M: IntoMatchString> IntoMatchString for Repeat<'_, M> {
48 type Matcher<'m> = Repeat<'m, M::Matcher<'m>>
49 where
50 Self: 'm;
51
52 fn into_match_string<'m>(self) -> Self::Matcher<'m>
53 where
54 Self: 'm,
55 {
56 let Self {
57 min,
58 max,
59 style,
60 inner,
61 ..
62 } = self;
63 Self::Matcher {
64 min,
65 max,
66 style,
67 inner: inner.into_match_string(),
68 links: default(),
69 }
70 }
71}
72
73impl<'m, M: MatchString<'m>> MatchString<'m> for Repeat<'m, M> {
74 fn match_string(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
75 let (outer, inner) = self.get_repeat_parts(cx);
76 cx.stack.extend([outer, inner]);
77
78 match self.style {
79 RepeatStyle::Greedy | RepeatStyle::Lazy => {
80 let mut state = cx.state();
81 let RepeatState {
82 repeat_index: last_repeat,
83 depth: last_depth,
84 ..
85 } = state.repeat;
86 let greedy = self.style == RepeatStyle::Greedy;
87 let repeat_index: u16 = cx
88 .stack
89 .len()
90 .try_into()
91 .expect("string matcher stack exceeded maximum size");
92 cx.stack.push(StackItem::Repeat {
93 min: self.min,
94 max: self.max,
95 greedy,
96 last_repeat,
97 last_depth,
98 });
99
100 state.repeat = RepeatState {
101 repeat_index,
102 depth: 0,
103 greedy,
104 min: self.min,
105 max: self.max,
106 };
107 cx.set_state(state).continue_repeat()
108 }
109 RepeatStyle::Simple => cx.continue_repeat_simple(self.min, self.max, 0),
110 }
111 }
112
113 fn links(&'m self) -> Option<super::Links<'m>> {
114 Some((&self.links).into())
115 }
116
117 fn initialize(&'m self) {
118 if self.style != RepeatStyle::Simple {
119 let next_matcher = Matcher::from(&RepeatContinue {});
120 self.inner.set_backward(Some(next_matcher));
121 self.inner.set_forward(Some(next_matcher));
122 }
123 self.inner.initialize()
124 }
125
126 fn fmt_matcher(&self, f: &mut fmt::Formatter, prec: DebugPrecedence) -> fmt::Result {
127 prec.wrap_below(DebugPrecedence::Mul, f, |f| {
128 self.inner.fmt_matcher(f, DebugPrecedence::Mul)?;
129 f.write_str(" * ")?;
130 match (self.min, self.max) {
131 (min, max) if min == max => write!(f, "{min}")?,
132 (0, u32::MAX) => f.write_str("..")?,
133 (0, max) => write!(f, "..={max}")?,
134 (min, u32::MAX) => write!(f, "{min}..")?,
135 (min, max) => write!(f, "{min}..={max}")?,
136 }
137 Ok(())
138 })
139 }
140
141 fn quick_test(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
142 let (outer, inner) = self.get_repeat_parts(cx);
143 let &Self { min, max, .. } = self;
144
145 let depth = if cx.is_reversed() { min } else { 0 };
146
147 cx.quick_test_repeat(outer, inner, depth, min, max, 1)
148 }
149}
150
151impl<'m> MatchString<'m> for RepeatContinue {
152 fn match_string(
153 &'m self,
154 cx: &mut super::machine::StringMatcherContext<'m, '_>,
155 ) -> Option<bool> {
156 cx.continue_repeat()
157 }
158
159 fn quick_test(&'m self, cx: &mut super::StringMatcherContext<'m, '_>) -> Option<bool> {
160 let RepeatState {
161 min,
162 max,
163 depth: mut repeat_depth,
164 ..
165 } = cx.state().repeat;
166 let (outer, inner) = cx.get_repeat_parts();
167
168 if cx.is_reversed() {
169 if repeat_depth == 0 {
170 return None;
171 }
172 repeat_depth -= 1;
173 } else {
174 repeat_depth = repeat_depth.saturating_add(1);
175 }
176
177 cx.quick_test_repeat(outer, inner, repeat_depth, min, max, 1)
178 }
179}
180
181pub trait RepeatCount {
182 fn bounds(&self) -> (Bound<&u32>, Bound<&u32>);
183}
184
185macro_rules! repeat_count_ranges {
186 ($($Name:ty),* $(,)?) => {
187 $(
188 impl RepeatCount for $Name {
189 fn bounds(&self) -> (Bound<&u32>, Bound<&u32>) {
190 (self.start_bound(), self.end_bound())
191 }
192 }
193 )*
194 impl_mul!($($Name,)*);
195 };
196}
197
198macro_rules! impl_mul {
199 ($($Name:ty),* $(,)?) => { $(
200 impl<M> core::ops::Mul<$Name> for StringPattern<M> {
201 type Output = StringPattern<Repeat<'static, M>>;
202
203 fn mul(self, rhs: $Name) -> Self::Output {
204 self.repeat(rhs)
205 }
206 }
207 impl<M> core::ops::Mul<StringPattern<M>> for $Name {
208 type Output = StringPattern<Repeat<'static, M>>;
209
210 fn mul(self, rhs: StringPattern<M>) -> Self::Output {
211 rhs * self
212 }
213 }
214 )* };
215}
216
217repeat_count_ranges!(
218 core::ops::RangeInclusive<u32>,
219 core::ops::RangeToInclusive<u32>,
220 core::ops::RangeFrom<u32>,
221 core::ops::RangeFull,
222);
223
224impl_mul!(u32);
225
226impl RepeatCount for u32 {
227 fn bounds(&self) -> (Bound<&u32>, Bound<&u32>) {
228 (Bound::Included(self), Bound::Included(self))
229 }
230}
231
232pub fn repeat<'m, M>(
234 count: impl RepeatCount,
235 inner: StringPattern<M>,
236) -> StringPattern<Repeat<'m, M>> {
237 inner.repeat(count)
238}
239
240pub fn optional<'m, M>(inner: StringPattern<M>) -> StringPattern<Repeat<'m, M>> {
242 inner.optional()
243}
244
245impl<M> StringPattern<M> {
246 pub fn repeat<'m>(self, count: impl RepeatCount) -> StringPattern<Repeat<'m, M>> {
247 let (start, end) = count.bounds();
248 let min = match start {
249 Bound::Included(&x) => x,
250 Bound::Excluded(&x) => x.saturating_add(1),
251 Bound::Unbounded => 0,
252 };
253 let max = match end {
254 Bound::Included(&x) => x,
255 Bound::Excluded(&x) => x.saturating_sub(1),
256 Bound::Unbounded => u32::MAX,
257 };
258 StringPattern::new(Repeat {
259 min,
260 max,
261 style: default(),
262 inner: self.inner,
263 links: default(),
264 })
265 }
266
267 pub fn optional<'m>(self) -> StringPattern<Repeat<'m, M>> {
268 self.repeat(..=1)
269 }
270}
271
272impl<'m, M> StringPattern<Repeat<'m, M>> {
273 pub fn greedy(mut self) -> Self {
276 self.inner.style = RepeatStyle::Greedy;
277 self
278 }
279 pub fn lazy(mut self) -> Self {
282 self.inner.style = RepeatStyle::Lazy;
283 self
284 }
285 pub fn simple(mut self) -> Self {
287 self.inner.style = RepeatStyle::Simple;
288 self
289 }
290}