litcheck_filecheck/pattern/
matches.rs1use crate::common::*;
2
3use super::iter::MatchIter;
4
5#[derive(Debug, Default)]
6pub struct Matches<'input>(SmallVec<[MatchResult<'input>; 1]>);
7impl<'input> Matches<'input> {
8 pub fn with_capacity(cap: usize) -> Self {
9 Self(SmallVec::with_capacity(cap))
10 }
11
12 #[inline]
13 pub fn len(&self) -> usize {
14 self.0.len()
15 }
16
17 #[inline]
18 pub fn is_empty(&self) -> bool {
19 self.0.is_empty()
20 }
21
22 #[inline]
23 pub fn as_slice(&self) -> &[MatchResult<'input>] {
24 self.0.as_slice()
25 }
26
27 pub fn is_ok(&self) -> bool {
29 self.0.iter().all(|mr| mr.is_ok())
30 }
31
32 pub fn has_errors(&self) -> bool {
34 !self.is_ok()
35 }
36
37 #[inline]
38 pub fn iter(&self) -> impl Iterator<Item = &MatchResult<'input>> + '_ {
39 self.0.iter()
40 }
41
42 #[inline]
43 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut MatchResult<'input>> + '_ {
44 self.0.iter_mut()
45 }
46
47 pub fn push(&mut self, result: MatchResult<'input>) {
48 use core::cmp::Ordering;
49
50 match self
51 .0
52 .binary_search_by(|probe| match (probe.info.as_ref(), result.info.as_ref()) {
53 (_, None) => Ordering::Less,
55 (None, Some(_)) => Ordering::Greater,
57 (Some(a), Some(b)) => a
58 .span
59 .start()
60 .cmp(&b.span.start())
61 .then_with(|| a.span.end().cmp(&b.span.end()))
62 .then_with(|| a.pattern_span.start().cmp(&b.pattern_span.start())),
63 }) {
64 Ok(index) | Err(index) => {
65 self.0.insert(index, result);
66 }
67 }
68 }
69
70 pub fn append(&mut self, matches: &mut Self) {
71 self.0.append(&mut matches.0);
72 self.sort();
73 }
74
75 pub fn extend<I>(&mut self, iter: I)
76 where
77 I: IntoIterator<Item = MatchResult<'input>>,
78 {
79 self.0.extend(iter);
80 }
81
82 pub fn range(&self) -> Option<Range<usize>> {
85 match self.0.as_slice() {
86 [MatchResult {
87 info: Some(info),
88 ty,
89 }] if ty.is_ok() => Some(info.matched_range()),
90 [MatchResult {
91 info: Some(info),
92 ty,
93 }, .., MatchResult {
94 info: Some(info2),
95 ty: ty2,
96 }] if ty.is_ok() && ty2.is_ok() => {
97 Some(Range::new(info.span.start(), info2.span.end()))
98 }
99 matches => matches
100 .iter()
101 .find_map(|mr| mr.matched_range())
102 .map(|start_range| {
103 matches
104 .iter()
105 .rev()
106 .find_map(|mr| {
107 mr.matched_range()
108 .map(|r| Range::new(start_range.start, r.end))
109 })
110 .unwrap_or(start_range)
111 }),
112 }
113 }
114
115 fn sort(&mut self) {
116 use core::cmp::Ordering;
117
118 self.0
119 .sort_unstable_by(|a, b| match (a.info.as_ref(), b.info.as_ref()) {
120 (None, None) => Ordering::Equal,
121 (Some(_), None) => Ordering::Less,
122 (None, Some(_)) => Ordering::Greater,
123 (Some(a), Some(b)) => a
124 .span
125 .start()
126 .cmp(&b.span.start())
127 .then_with(|| a.span.end().cmp(&b.span.end()))
128 .then_with(|| a.pattern_span.start().cmp(&b.pattern_span.start())),
129 });
130 }
131}
132impl<'input> From<MatchResult<'input>> for Matches<'input> {
133 fn from(result: MatchResult<'input>) -> Self {
134 Self(smallvec![result])
135 }
136}
137impl<'input> FromIterator<MatchResult<'input>> for Matches<'input> {
138 fn from_iter<T>(iter: T) -> Self
139 where
140 T: IntoIterator<Item = MatchResult<'input>>,
141 {
142 let mut matches = Self(SmallVec::from_iter(iter));
143 matches.sort();
144 matches
145 }
146}
147impl<'input> IntoIterator for Matches<'input> {
148 type Item = Result<Option<MatchInfo<'input>>, CheckFailedError>;
149 type IntoIter = MatchIter<'input, 1>;
150
151 #[inline]
152 fn into_iter(self) -> Self::IntoIter {
153 MatchIter::new(self.0.into_iter())
154 }
155}