tracexec_core/primitives/
regex.rs1use std::sync::LazyLock;
2
3pub use regex_cursor::*;
5
6use crate::event::OutputMsg;
7
8pub trait BidirectionalIterator: Iterator {
9 fn prev(&mut self) -> Option<Self::Item>;
10}
11
12pub trait IntoBidirectionalIterator {
13 type Iter: BidirectionalIterator;
14
15 fn into_bidirectional_iter(self) -> Self::Iter;
16}
17
18pub struct BidirectionalIter<'a, T> {
19 slice: &'a [T],
20 index: BidirectionalIterIndex,
21}
22
23impl<'a, T> BidirectionalIter<'a, T> {
24 fn new(slice: &'a [T]) -> Self {
25 Self {
26 slice,
27 index: BidirectionalIterIndex::Start,
28 }
29 }
30}
31
32impl<T> BidirectionalIter<'_, T> {
33 pub fn by_ref(&mut self) -> &mut Self {
34 self
35 }
36}
37
38impl<'a, T> Iterator for BidirectionalIter<'a, T> {
39 type Item = &'a T;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 self.index.next(self.slice.len());
43 self.index.get(self.slice)
44 }
45}
46
47impl<T> BidirectionalIterator for BidirectionalIter<'_, T> {
48 fn prev(&mut self) -> Option<Self::Item> {
49 self.index.prev(self.slice.len());
50 self.index.get(self.slice)
51 }
52}
53
54enum BidirectionalIterIndex {
55 Start,
56 Index(usize),
57 End,
58}
59
60impl BidirectionalIterIndex {
61 fn next(&mut self, len: usize) {
62 match self {
63 Self::Start => {
64 *self = if len > 0 { Self::Index(0) } else { Self::Start };
65 }
66 Self::Index(index) => {
67 if *index + 1 < len {
68 *index += 1;
69 } else {
70 *self = Self::End;
71 }
72 }
73 Self::End => {}
74 }
75 }
76
77 fn prev(&mut self, len: usize) {
78 match self {
79 Self::Start => {}
80 Self::Index(index) => {
81 if *index > 0 {
82 *index -= 1;
83 } else {
84 *self = Self::Start;
85 }
86 }
87 Self::End => {
88 *self = Self::Index(len.saturating_sub(1));
89 }
90 }
91 }
92
93 fn get<'a, T>(&self, slice: &'a [T]) -> Option<&'a T> {
94 match self {
95 Self::Start => None,
96 Self::Index(index) => slice.get(*index),
97 Self::End => None,
98 }
99 }
100}
101
102impl<'a, T> IntoBidirectionalIterator for &'a [T] {
103 type Iter = BidirectionalIter<'a, T>;
104
105 fn into_bidirectional_iter(self) -> Self::Iter {
106 BidirectionalIter::new(self)
107 }
108}
109
110enum BidirectionalInterspersedIterIndex {
111 Start,
112 Index(usize),
113 Separator(usize),
115 End,
116}
117
118pub struct BidirectionalInterspersedIter<'a, T> {
119 slice: &'a [T],
120 index: BidirectionalInterspersedIterIndex,
121 separator: &'a T,
122}
123
124impl<'a, T> BidirectionalInterspersedIter<'a, T> {
125 fn new(slice: &'a [T], separator: &'a T) -> Self {
126 Self {
127 slice,
128 index: BidirectionalInterspersedIterIndex::Start,
129 separator,
130 }
131 }
132}
133
134impl BidirectionalInterspersedIterIndex {
135 fn next(&mut self, len: usize) {
136 match self {
137 Self::Start => {
138 *self = if len > 0 { Self::Index(0) } else { Self::Start };
139 }
140 Self::Index(index) => {
141 if *index + 1 < len {
142 *self = Self::Separator(*index)
144 } else {
145 *self = Self::End;
146 }
147 }
148 Self::End => {}
149 Self::Separator(index) => *self = Self::Index(*index + 1),
150 }
151 }
152
153 fn prev(&mut self, len: usize) {
154 match self {
155 Self::Start => {}
156 Self::Index(index) => {
157 if *index > 0 {
158 *self = Self::Separator(*index - 1)
160 } else {
161 *self = Self::Start;
162 }
163 }
164 Self::End => {
165 if len > 0 {
166 *self = Self::Index(len.saturating_sub(1));
167 } else {
168 *self = Self::Start;
169 }
170 }
171 Self::Separator(index) => *self = Self::Index(*index),
172 }
173 }
174
175 fn get<'a, T>(&self, slice: &'a [T], separator: &'a T) -> Option<&'a T> {
176 match self {
177 Self::Start => None,
178 Self::Index(index) => slice.get(*index),
179 Self::Separator(_) => Some(separator),
180 Self::End => None,
181 }
182 }
183}
184
185impl<'a, T> Iterator for BidirectionalInterspersedIter<'a, T> {
186 type Item = &'a T;
187
188 fn next(&mut self) -> Option<Self::Item> {
189 self.index.next(self.slice.len());
190 self.index.get(self.slice, self.separator)
191 }
192}
193
194impl<T> BidirectionalIterator for BidirectionalInterspersedIter<'_, T> {
195 fn prev(&mut self) -> Option<Self::Item> {
196 self.index.prev(self.slice.len());
197 self.index.get(self.slice, self.separator)
198 }
199}
200
201#[cfg(test)]
202mod iter_tests {
203 use super::BidirectionalInterspersedIter;
204 use super::BidirectionalIterator;
205
206 #[test]
207 fn biter_interspersed_roundtrip() {
208 let slice = [1, 2, 3, 4];
209 let separator = 0;
210 let mut biter = BidirectionalInterspersedIter::new(&slice, &separator);
211 assert_eq!(biter.next(), Some(&1));
212 assert_eq!(biter.next(), Some(&0));
213 assert_eq!(biter.next(), Some(&2));
214 assert_eq!(biter.next(), Some(&0));
215 assert_eq!(biter.next(), Some(&3));
216 assert_eq!(biter.next(), Some(&0));
217 assert_eq!(biter.next(), Some(&4));
218 assert_eq!(biter.next(), None);
219 assert_eq!(biter.prev(), Some(&4));
220 assert_eq!(biter.prev(), Some(&0));
221 assert_eq!(biter.prev(), Some(&3));
222 assert_eq!(biter.prev(), Some(&0));
223 assert_eq!(biter.prev(), Some(&2));
224 assert_eq!(biter.prev(), Some(&0));
225 assert_eq!(biter.prev(), Some(&1));
226 assert_eq!(biter.prev(), None);
227 }
228
229 #[test]
230 fn biter_interspersed_two_items() {
231 let slice = [1, 2];
232 let separator = 0;
233 let mut biter = BidirectionalInterspersedIter::new(&slice, &separator);
234 assert_eq!(biter.next(), Some(&1));
235 assert_eq!(biter.next(), Some(&0));
236 assert_eq!(biter.next(), Some(&2));
237 assert_eq!(biter.prev(), Some(&0));
238 assert_eq!(biter.next(), Some(&2));
239 assert_eq!(biter.next(), None);
240 assert_eq!(biter.next(), None);
241 assert_eq!(biter.prev(), Some(&2));
242 assert_eq!(biter.prev(), Some(&0));
243 assert_eq!(biter.prev(), Some(&1));
244 assert_eq!(biter.prev(), None);
245 assert_eq!(biter.prev(), None);
246 assert_eq!(biter.next(), Some(&1));
247 assert_eq!(biter.next(), Some(&0));
248 assert_eq!(biter.prev(), Some(&1));
249 }
250
251 #[test]
252 fn biter_interspersed_single_item() {
253 let slice = [1];
254 let separator = 0;
255 let mut biter = BidirectionalInterspersedIter::new(&slice, &separator);
256 assert_eq!(biter.next(), Some(&1));
257 assert_eq!(biter.next(), None);
258 assert_eq!(biter.next(), None);
259 assert_eq!(biter.prev(), Some(&1));
260 assert_eq!(biter.prev(), None);
261 }
262}
263
264#[derive(Debug, Clone, Copy, PartialEq, Eq)]
293enum CursorPosition {
294 ChunkStart,
295 ChunkEnd,
296}
297
298pub struct ArgvCursor<'a, T> {
300 iter: BidirectionalInterspersedIter<'a, T>,
301 current: &'a [u8],
302 position: CursorPosition,
303 len: usize,
304 offset: usize,
305}
306
307pub static SPACE: LazyLock<OutputMsg> = LazyLock::new(|| OutputMsg::Ok(" ".into()));
308
309impl<'a, T> ArgvCursor<'a, T>
310where
311 T: AsRef<str>,
312{
313 pub fn new(slice: &'a [T], separator: &'a T) -> Self {
314 let mut res = Self {
315 iter: BidirectionalInterspersedIter::new(slice, separator),
316 current: &[],
317 position: CursorPosition::ChunkEnd,
318 len: slice.iter().map(|s| s.as_ref().len()).sum::<usize>()
319 + (slice.len().saturating_sub(1)) * separator.as_ref().len(),
320 offset: 0,
321 };
322 res.advance();
323 res
324 }
325}
326
327impl<T> Cursor for ArgvCursor<'_, T>
328where
329 T: AsRef<str>,
330{
331 fn chunk(&self) -> &[u8] {
332 self.current
333 }
334
335 fn advance(&mut self) -> bool {
336 match self.position {
337 CursorPosition::ChunkStart => {
338 self.iter.next();
339 self.position = CursorPosition::ChunkEnd;
340 }
341 CursorPosition::ChunkEnd => (),
342 }
343 for next in self.iter.by_ref() {
344 if next.as_ref().is_empty() {
345 continue;
346 }
347 self.offset += self.current.len();
348 self.current = next.as_ref().as_bytes();
349 return true;
350 }
351 false
352 }
353
354 fn backtrack(&mut self) -> bool {
355 match self.position {
356 CursorPosition::ChunkStart => {}
357 CursorPosition::ChunkEnd => {
358 self.iter.prev();
359 self.position = CursorPosition::ChunkStart;
360 }
361 }
362 while let Some(prev) = self.iter.prev() {
363 if prev.as_ref().is_empty() {
364 continue;
365 }
366 self.offset -= prev.as_ref().len();
367 self.current = prev.as_ref().as_bytes();
368 return true;
369 }
370 false
371 }
372
373 fn total_bytes(&self) -> Option<usize> {
374 Some(self.len)
375 }
376
377 fn offset(&self) -> usize {
378 self.offset
379 }
380}
381
382#[cfg(test)]
383mod cursor_tests {
384 use super::*;
385 use crate::cache::ArcStr;
386
387 #[test]
388 fn smoke_test() {
389 let single = vec![ArcStr::from("abc")];
390 let separator = " ".into();
391 let mut cursor = ArgvCursor::new(single.as_slice(), &separator);
392 assert_eq!(cursor.chunk(), b"abc");
393 assert!(!cursor.advance());
394 assert_eq!(cursor.chunk(), b"abc");
395 assert!(!cursor.backtrack());
396 assert_eq!(cursor.chunk(), b"abc");
397 let two = vec![ArcStr::from("abc"); 2];
399 let mut cursor = ArgvCursor::new(two.as_slice(), &separator);
400 let mut offset = 0;
401 loop {
402 assert_eq!(cursor.offset(), offset);
403 offset += cursor.chunk().len();
404 if !cursor.advance() {
405 break;
406 }
407 }
408 loop {
409 offset -= cursor.chunk().len();
410 assert_eq!(cursor.offset(), offset);
411 if !cursor.backtrack() {
412 break;
413 }
414 }
415 assert_eq!(cursor.offset(), 0);
416 assert_eq!(offset, 0);
417 let multi = vec![ArcStr::from("abc"); 100];
419 let mut cursor = ArgvCursor::new(multi.as_slice(), &separator);
420 let mut offset = 0;
421 loop {
422 assert_eq!(cursor.offset(), offset);
423 offset += cursor.chunk().len();
424 if !cursor.advance() {
425 break;
426 }
427 }
428 loop {
429 offset -= cursor.chunk().len();
430 assert_eq!(cursor.offset(), offset);
431 if !cursor.backtrack() {
432 break;
433 }
434 }
435 assert_eq!(cursor.offset(), 0);
436 assert_eq!(offset, 0);
437 }
438}