1use std::borrow::Cow;
14use std::collections::HashMap;
15use std::fmt;
16use std::hash::Hash;
17use std::sync::Arc;
18use std::sync::OnceLock;
19use std::sync::RwLock;
20
21use bitflags::bitflags;
22
23#[derive(Clone, PartialEq, Eq, Debug)]
25pub enum Item<T> {
26 Tree(T, Vec<Item<T>>),
27 Item(T),
28 Placeholder(Placeholder<T>),
29}
30
31#[derive(Clone)]
37pub struct Placeholder<T> {
38 name: String,
39 matches_item: Option<Arc<dyn (Fn(&Item<T>) -> bool) + 'static>>,
42 matches_multiple: bool,
45}
46
47impl<T> PartialEq for Placeholder<T> {
48 fn eq(&self, other: &Self) -> bool {
49 self.name == other.name
50 }
51}
52
53impl<T> Eq for Placeholder<T> {}
54
55impl<T> fmt::Debug for Placeholder<T> {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 self.name.fmt(f)
58 }
59}
60
61impl<T> Placeholder<T> {
62 pub fn new(name: String) -> Self {
63 let matches_multiple = name.starts_with("___");
64 Self {
65 name,
66 matches_item: None,
67 matches_multiple,
68 }
69 }
70
71 pub fn set_matches_item(
72 &mut self,
73 matches_item: impl (Fn(&Item<T>) -> bool) + 'static,
74 ) -> &mut Self {
75 self.matches_item = Some(Arc::new(matches_item));
76 self
77 }
78
79 pub fn set_matches_multiple(&mut self, matches_multiple: bool) -> &mut Self {
80 self.matches_multiple = matches_multiple;
81 self
82 }
83
84 pub fn name(&self) -> &str {
85 self.name.as_str()
86 }
87
88 pub fn matches_multiple(&self) -> bool {
90 self.matches_multiple
91 }
92
93 pub fn matches_item(&self, item: &Item<T>) -> bool {
95 match self.matches_item.as_ref() {
96 None => true,
97 Some(f) => f(item),
98 }
99 }
100}
101
102pub trait PlaceholderExt<T> {
103 fn with_placeholder_matching_items<F: Fn(&Item<T>) -> bool + 'static>(
104 self,
105 name_matches_item_pairs: impl IntoIterator<Item = (&'static str, F)>,
106 ) -> Self;
107}
108
109impl<T> PlaceholderExt<T> for Vec<Item<T>> {
110 fn with_placeholder_matching_items<F: Fn(&Item<T>) -> bool + 'static>(
111 mut self,
112 name_matches_item_pairs: impl IntoIterator<Item = (&'static str, F)>,
113 ) -> Self {
114 fn rewrite_items<T, F: Fn(&Item<T>) -> bool + 'static>(
115 items: &mut [Item<T>],
116 mapping: &mut HashMap<&str, F>,
117 ) {
118 for item in items.iter_mut() {
119 match item {
120 Item::Placeholder(p) => {
121 if let Some(f) = mapping.remove(p.name()) {
122 p.set_matches_item(f);
123 }
124 }
125 Item::Tree(_, children) => {
126 rewrite_items(children, mapping);
127 }
128 _ => {}
129 }
130 }
131 }
132
133 let mut mapping: HashMap<&str, F> = name_matches_item_pairs.into_iter().collect();
134 rewrite_items(&mut self, &mut mapping);
135 self
136 }
137}
138
139#[derive(Debug, Clone, Eq, PartialEq)]
141pub struct Match<T> {
142 end: usize,
144 start: usize,
146 pub captures: Captures<T>,
148}
149type Captures<T> = HashMap<String, Vec<Item<T>>>;
150
151impl<T> Default for Match<T> {
153 fn default() -> Self {
154 Self {
155 end: 0,
156 start: 0,
157 captures: Default::default(),
158 }
159 }
160}
161
162pub fn replace_all<T: fmt::Debug + Clone + PartialEq + 'static>(
164 items: &[Item<T>],
165 pat: &[Item<T>],
166 replace: impl Replace<T>,
167) -> Vec<Item<T>> {
168 TreeMatchState::default()
169 .replace_all(items, pat, &replace)
170 .into_owned()
171}
172
173pub fn find_all<T: fmt::Debug + Clone + PartialEq>(
175 items: &[Item<T>],
176 pat: &[Item<T>],
177) -> Vec<Match<T>> {
178 TreeMatchState::default().find_all(items, pat)
179}
180
181pub fn matches_start<T: fmt::Debug + Clone + PartialEq>(
183 items: &[Item<T>],
184 pat: &[Item<T>],
185) -> Option<Match<T>> {
186 TreeMatchState::default().find_one(items, pat, TreeMatchMode::MatchBegin)
187}
188
189pub fn matches_full<T: fmt::Debug + Clone + PartialEq>(
191 items: &[Item<T>],
192 pat: &[Item<T>],
193) -> Option<Match<T>> {
194 TreeMatchState::default().find_one(items, pat, TreeMatchMode::MatchFull)
195}
196
197pub trait Replace<T> {
199 fn expand(&self, m: &Match<T>) -> Vec<Item<T>>;
200}
201
202impl<T: Clone> Replace<T> for &[Item<T>] {
203 fn expand(&self, m: &Match<T>) -> Vec<Item<T>> {
204 expand_replace(self, &m.captures)
205 }
206}
207
208impl<T: Clone> Replace<T> for &Vec<Item<T>> {
209 fn expand(&self, m: &Match<T>) -> Vec<Item<T>> {
210 expand_replace(self, &m.captures)
211 }
212}
213
214impl<T: Clone> Replace<T> for Vec<Item<T>> {
215 fn expand(&self, m: &Match<T>) -> Vec<Item<T>> {
216 expand_replace(self, &m.captures)
217 }
218}
219
220impl<T, F> Replace<T> for F
221where
222 F: Fn(&'_ Match<T>) -> Vec<Item<T>>,
223{
224 fn expand(&self, m: &Match<T>) -> Vec<Item<T>> {
225 (self)(m)
226 }
227}
228
229fn expand_replace<T: Clone>(replace: &[Item<T>], captures: &Captures<T>) -> Vec<Item<T>> {
231 let mut result = Vec::with_capacity(replace.len());
232 for item in replace {
233 match item {
234 Item::Tree(delimiter, sub_items) => {
235 let sub_expanded = expand_replace(sub_items, captures);
236 let new_tree = Item::Tree(delimiter.clone(), sub_expanded);
237 result.push(new_tree);
238 }
239 Item::Placeholder(p) => {
240 if let Some(items) = captures.get(p.name()) {
241 result.extend_from_slice(items);
242 }
243 }
244 _ => result.push(item.clone()),
245 }
246 }
247 result
248}
249
250#[derive(Clone)]
252struct TreeMatchState<'a, T> {
253 cache: Arc<RwLock<HashMap<TreeMatchCacheKey, Arc<SeqMatchState<'a, T>>>>>,
256}
257
258#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
260struct TreeMatchCacheKey {
261 pat: (usize, usize),
262 items: (usize, usize),
263 opts: TreeMatchMode,
264}
265
266struct SeqMatchState<'a, T> {
268 parent: TreeMatchState<'a, T>,
269 cache: Vec<SeqMatched>,
270 pat: &'a [Item<T>],
271 items: &'a [Item<T>],
272 match_end: Option<usize>,
274 match_ends: Vec<usize>,
276}
277
278#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
280enum TreeMatchMode {
281 MatchFull,
283 MatchBegin,
285 Search,
288}
289
290bitflags! {
291 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
294 struct SeqMatched: u8 {
295 const MATCH_ITEM = 1;
297 const MATCH_TREE = 2;
299 const MATCH_PLACEHOLDER_SINGLE = 4;
301 const MATCH_PLACEHOLDER_MULTI = 8;
303 const MATCH_PLACEHOLDER_MULTI_EXTEND = 16;
305 const MATCH_INIT = 32;
307 const UNKNOWN = 128;
309 }
310}
311
312impl<'a, T> Default for TreeMatchState<'a, T> {
314 fn default() -> Self {
315 Self {
316 cache: Default::default(),
317 }
318 }
319}
320
321impl TreeMatchCacheKey {
322 fn new<T>(pat: &[T], items: &[T], opts: TreeMatchMode) -> Self {
323 Self {
324 pat: (pat.as_ptr() as usize, pat.len()),
325 items: (items.as_ptr() as usize, items.len()),
326 opts,
327 }
328 }
329}
330
331impl SeqMatched {
332 fn has_match(self) -> bool {
333 !self.is_empty()
334 }
335}
336
337impl<'a, T: PartialEq + Clone + fmt::Debug> SeqMatchState<'a, T> {
338 fn matched(&mut self, pat_end: usize, item_end: usize, opts: TreeMatchMode) -> SeqMatched {
343 let cached = *self.get_cache_mut(pat_end, item_end);
344 if cached != SeqMatched::UNKNOWN {
345 return cached;
346 }
347 let result = match (pat_end, item_end) {
348 (0, 0) => SeqMatched::MATCH_INIT,
349 (0, _) if matches!(opts, TreeMatchMode::Search) => {
350 SeqMatched::MATCH_INIT
352 }
353 (1, 0) if matches!(&self.pat[pat_end - 1], Item::Placeholder(p) if p.matches_multiple()) => {
354 SeqMatched::MATCH_PLACEHOLDER_MULTI
355 }
356 (_, 0) | (0, _) => SeqMatched::empty(),
357 _ => {
358 let mut result = SeqMatched::empty();
359 match &self.pat[pat_end - 1] {
360 Item::Tree(t1, pat_children) => {
361 if let Item::Tree(t2, item_children) = &self.items[item_end - 1] {
362 if t1 == t2 && self.matched(pat_end - 1, item_end - 1, opts).has_match() && self.parent.matched(pat_children, item_children, TreeMatchMode::MatchFull).has_match()
364 {
365 result |= SeqMatched::MATCH_TREE;
366 }
367 }
368 }
369 Item::Item(t1) => {
370 if matches!(&self.items[item_end - 1], Item::Item(t2) if t1 == t2)
371 && self.matched(pat_end - 1, item_end - 1, opts).has_match()
372 {
373 result |= SeqMatched::MATCH_ITEM;
374 }
375 }
376 Item::Placeholder(p) => {
377 if p.matches_multiple() {
378 if self.matched(pat_end - 1, item_end, opts).has_match() {
382 result |= SeqMatched::MATCH_PLACEHOLDER_MULTI;
383 }
384 let m = self.matched(pat_end, item_end - 1, opts);
388 if m.intersects(
389 SeqMatched::MATCH_PLACEHOLDER_MULTI
390 | SeqMatched::MATCH_PLACEHOLDER_MULTI_EXTEND,
391 ) {
392 if p.matches_item(&self.items[item_end - 1]) {
393 result |= SeqMatched::MATCH_PLACEHOLDER_MULTI_EXTEND;
394 }
395 }
396 } else if p.matches_item(&self.items[item_end - 1])
397 && self.matched(pat_end - 1, item_end - 1, opts).has_match()
398 {
399 result |= SeqMatched::MATCH_PLACEHOLDER_SINGLE;
400 }
401 }
402 };
403 result
404 }
405 };
406 assert!(!result.contains(SeqMatched::UNKNOWN));
407 *self.get_cache_mut(pat_end, item_end) = result;
408 result
409 }
410
411 fn fill_match(&self, r#match: &mut Match<T>) {
413 self.fill_match_with_match_end(r#match, None, true);
414 }
415
416 fn fill_matches(&self, matches: &mut Vec<Match<T>>) {
424 for &end in &self.match_ends {
425 let mut m = Match::default();
426 self.fill_match_with_match_end(&mut m, Some(end), true);
427 matches.push(m);
428 }
429 }
430
431 fn backtrack_match_start(&self, end: usize) -> usize {
433 let mut m = Match::default();
434 self.fill_match_with_match_end(&mut m, Some(end), false);
435 assert_eq!(m.end, end, "find_match_start requires 'end' to be a match");
436 m.start
437 }
438
439 fn fill_match_with_match_end(
441 &self,
442 r#match: &mut Match<T>,
443 match_end: Option<usize>,
444 fill_captures: bool,
445 ) {
446 let mut pat_len = self.pat.len();
447 let mut multi_len = 0;
448 let match_end = match_end.unwrap_or_else(|| self.match_end.unwrap());
449 let mut item_len = match_end;
450 loop {
451 let mut item_dec = 1;
452 let matched = self.get_cache(pat_len, item_len);
453 if matched.contains(SeqMatched::MATCH_ITEM) {
454 pat_len -= 1;
455 } else if matched.contains(SeqMatched::MATCH_TREE) {
456 if let (Item::Tree(_, pat_children), Item::Tree(_, item_children)) =
457 (&self.pat[pat_len - 1], &self.items[item_len - 1])
458 {
459 if fill_captures {
460 self.parent
461 .matched(pat_children, item_children, TreeMatchMode::MatchFull)
462 .fill_match_with_match_end(r#match, None, fill_captures);
463 }
464 pat_len -= 1;
465 } else {
466 unreachable!("bug: MATCH_TREE does not actually match trees");
467 }
468 } else if matched.contains(SeqMatched::MATCH_PLACEHOLDER_MULTI_EXTEND) {
469 multi_len += 1;
470 } else if matched.intersects(
471 SeqMatched::MATCH_PLACEHOLDER_MULTI | SeqMatched::MATCH_PLACEHOLDER_SINGLE,
472 ) {
473 let (start, len) = if matched.intersects(SeqMatched::MATCH_PLACEHOLDER_SINGLE) {
474 (item_len - 1, 1)
475 } else {
476 item_dec = 0;
477 (item_len, multi_len)
478 };
479 if let Item::Placeholder(p) = &self.pat[pat_len - 1] {
480 if fill_captures {
481 r#match.captures.insert(
482 p.name().to_string(),
483 self.items[start..start + len].to_vec(),
484 );
485 }
486 } else {
487 unreachable!("bug: MATCH_PLACEHOLDER does not actually match a placeholder");
488 }
489 pat_len -= 1;
490 multi_len = 0;
491 }
492 if pat_len == 0 && item_len > 0 {
493 item_len -= item_dec;
494 break;
495 }
496 if item_len == 0 {
497 break;
498 } else {
499 item_len -= item_dec;
500 }
501 }
502 r#match.start = item_len;
503 r#match.end = match_end;
504 }
505
506 fn get_cache_mut(&mut self, pat_end: usize, item_end: usize) -> &mut SeqMatched {
508 debug_assert!(pat_end <= self.pat.len() && item_end <= self.items.len());
509 &mut self.cache[(item_end) * (self.pat.len() + 1) + pat_end]
510 }
511
512 fn get_cache(&self, pat_end: usize, item_end: usize) -> SeqMatched {
513 debug_assert!(pat_end <= self.pat.len() && item_end <= self.items.len());
514 self.cache[(item_end) * (self.pat.len() + 1) + pat_end]
515 }
516
517 fn clear_cache_range(&mut self, item_start: usize, item_end: usize) {
519 let pat_len = self.pat.len() + 1;
520 let start = item_start * pat_len;
521 let end = item_end * pat_len;
522 self.cache[start..end].fill(SeqMatched::UNKNOWN);
523 }
524
525 fn cut_off_matches_at(&mut self, end: usize) {
528 for i in 0..self.pat.len() {
531 let matched = match i {
532 0 => SeqMatched::MATCH_INIT,
533 1 if matches!(self.pat.first(), Some(Item::Placeholder(p)) if p.matches_multiple()) => {
534 SeqMatched::MATCH_PLACEHOLDER_MULTI
535 }
536 _ => SeqMatched::empty(),
537 };
538 *self.get_cache_mut(i, end) = matched;
539 }
540 }
543
544 fn has_match(&self) -> bool {
545 self.match_end.is_some()
546 }
547}
548
549impl<'a, T: PartialEq + Clone + fmt::Debug> TreeMatchState<'a, T> {
550 fn matched(
552 &self,
553 pat: &'a [Item<T>],
554 items: &'a [Item<T>],
555 opts: TreeMatchMode,
556 ) -> Arc<SeqMatchState<'a, T>> {
557 let key = TreeMatchCacheKey::new(pat, items, opts);
558 if let Some(cached) = self.cache.read().unwrap().get(&key) {
559 return cached.clone();
560 }
561
562 let parent = self.clone();
563 let cache = vec![SeqMatched::UNKNOWN; (items.len() + 1) * (pat.len() + 1)];
564 let mut seq = SeqMatchState {
565 parent,
566 cache,
567 pat,
568 items,
569 match_end: None,
570 match_ends: Default::default(),
571 };
572 match opts {
573 TreeMatchMode::MatchFull => {
574 if !seq.matched(pat.len(), items.len(), opts).is_empty() {
575 seq.match_end = Some(items.len());
576 }
577 }
578 TreeMatchMode::MatchBegin | TreeMatchMode::Search => {
579 let is_search = opts == TreeMatchMode::Search;
581 let mut last_cutoff = 0;
582 'next: for end in 1..=items.len() {
583 'retry: loop {
584 if !seq.matched(pat.len(), end, opts).is_empty() {
585 if is_search {
586 if let Some(&last_end) = seq.match_ends.last() {
589 let start = seq.backtrack_match_start(end);
590 let last_start = seq.backtrack_match_start(last_end);
591 if last_start >= start {
592 seq.match_ends.pop();
594 } else if last_end > start {
595 if last_cutoff < last_end {
597 seq.clear_cache_range(last_end + 1, end + 1);
599 seq.cut_off_matches_at(last_end);
600 last_cutoff = last_end;
601 continue 'retry;
602 } else {
603 continue 'next;
605 }
606 }
607 }
608 seq.match_ends.push(end);
609 }
610 seq.match_end = Some(end);
611 }
612 break;
613 }
614 }
615 }
616 }
617 self.cache
618 .write()
619 .unwrap()
620 .entry(key)
621 .or_insert(Arc::new(seq))
622 .clone()
623 }
624
625 fn find_all(&self, items: &'a [Item<T>], pat: &'a [Item<T>]) -> Vec<Match<T>> {
626 let matched = self.matched(pat, items, TreeMatchMode::Search);
627 let mut result = Vec::new();
628 matched.fill_matches(&mut result);
629 let current_depth_matches_len = result.len();
630 for (i, item) in items.iter().enumerate() {
632 if let Item::Tree(.., children) = item {
633 if is_covered(i, &result[..current_depth_matches_len]) {
634 continue;
636 }
637 result.extend(self.find_all(children, pat));
638 }
639 }
640 result
641 }
642
643 fn find_one(
644 &self,
645 items: &'a [Item<T>],
646 pat: &'a [Item<T>],
647 mode: TreeMatchMode,
648 ) -> Option<Match<T>> {
649 let matched = self.matched(pat, items, mode);
650 matched.match_end.map(|_| {
651 let mut m = Match::default();
652 matched.fill_match(&mut m);
653 m
654 })
655 }
656}
657
658impl<'a, T: PartialEq + Clone + fmt::Debug + 'static> TreeMatchState<'a, T> {
659 fn replace_all(
660 &self,
661 items: &'a [Item<T>],
662 pat: &'a [Item<T>],
663 replace: &dyn Replace<T>,
664 ) -> Cow<'a, [Item<T>]> {
665 let matched = self.matched(pat, items, TreeMatchMode::Search);
666
667 let mut matches = Vec::new();
669 let mut replaced = MaybeOwned::<T>(OnceLock::new());
670 matched.fill_matches(&mut matches);
671
672 for (i, item) in items.iter().enumerate() {
675 if let Item::Tree(t, children) = item {
676 if is_covered(i, &matches) {
677 continue;
679 }
680 let new_children = self.replace_all(children, pat, replace);
681 if is_owned(&new_children) {
682 replaced.maybe_init(items);
683 replaced.as_mut()[i] = Item::Tree(t.clone(), new_children.into_owned());
684 }
685 }
686 }
687
688 if !matches.is_empty() {
690 let mut new_items = Vec::with_capacity(items.len());
691 let mut end = 0;
692 for m in matches {
693 new_items.extend_from_slice(replaced.slice(items, end, m.start));
694 let replaced = replace.expand(&m);
695 new_items.extend(replaced);
696 end = m.end;
697 }
698 new_items.extend_from_slice(replaced.slice(items, end, items.len()));
699 replaced.0 = new_items.into();
700 }
701
702 match replaced.0.into_inner() {
703 None => Cow::Borrowed(items),
704 Some(items) => Cow::Owned(items),
705 }
706 }
707}
708
709struct MaybeOwned<T>(OnceLock<Vec<Item<T>>>);
711
712impl<T: Clone + 'static> MaybeOwned<T> {
713 fn maybe_init(&self, init_value: &[Item<T>]) {
714 self.0.get_or_init(|| init_value.to_vec());
715 }
716
717 fn slice<'a>(&'a self, fallback: &'a [Item<T>], start: usize, end: usize) -> &'a [Item<T>] {
718 match self.0.get() {
719 None => &fallback[start..end],
720 Some(v) => &v[start..end],
721 }
722 }
723}
724
725impl<T: Clone + 'static> MaybeOwned<T> {
726 fn as_mut(&mut self) -> &mut Vec<Item<T>> {
727 self.0.get_mut().unwrap()
728 }
729}
730
731#[allow(clippy::ptr_arg)]
733fn is_owned<T: ToOwned + ?Sized>(value: &Cow<'_, T>) -> bool {
734 matches!(value, Cow::Owned(_))
735}
736
737fn is_covered<T>(index: usize, sorted_matches: &[Match<T>]) -> bool {
738 let m = match sorted_matches.binary_search_by_key(&index, |m| m.start) {
739 Ok(idx) => sorted_matches.get(idx),
740 Err(idx) => sorted_matches.get(idx.saturating_sub(1)),
741 };
742 if let Some(m) = m {
743 if m.start <= index && m.end > index {
744 return true;
745 }
746 }
747 false
748}