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(always)]
38 pub fn into_results(self) -> SmallVec<[MatchResult<'input>; 1]> {
39 self.0
40 }
41
42 #[inline]
43 pub fn iter(&self) -> impl Iterator<Item = &MatchResult<'input>> + '_ {
44 self.0.iter()
45 }
46
47 #[inline]
48 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut MatchResult<'input>> + '_ {
49 self.0.iter_mut()
50 }
51
52 pub fn push(&mut self, result: MatchResult<'input>) {
53 use core::cmp::Ordering;
54
55 match self
56 .0
57 .binary_search_by(|probe| match (probe.info.as_ref(), result.info.as_ref()) {
58 (_, None) => Ordering::Less,
60 (None, Some(_)) => Ordering::Greater,
62 (Some(a), Some(b)) => a
63 .span
64 .start()
65 .cmp(&b.span.start())
66 .then_with(|| a.span.end().cmp(&b.span.end()))
67 .then_with(|| a.pattern_span.start().cmp(&b.pattern_span.start())),
68 }) {
69 Ok(index) | Err(index) => {
70 self.0.insert(index, result);
71 }
72 }
73 }
74
75 pub fn append(&mut self, matches: &mut Self) {
76 self.0.append(&mut matches.0);
77 self.sort();
78 }
79
80 pub fn extend<I>(&mut self, iter: I)
81 where
82 I: IntoIterator<Item = MatchResult<'input>>,
83 {
84 self.0.extend(iter);
85 }
86
87 pub fn range(&self) -> Option<Range<usize>> {
90 match self.0.as_slice() {
91 [
92 MatchResult {
93 info: Some(info),
94 ty,
95 },
96 ] if ty.is_ok() => Some(info.matched_range()),
97 [
98 MatchResult {
99 info: Some(info),
100 ty,
101 },
102 ..,
103 MatchResult {
104 info: Some(info2),
105 ty: ty2,
106 },
107 ] if ty.is_ok() && ty2.is_ok() => Some(Range::new(
108 info.span.start().to_usize(),
109 info2.span.end().to_usize(),
110 )),
111 matches => matches
112 .iter()
113 .find_map(|mr| mr.matched_range())
114 .map(|start_range| {
115 matches
116 .iter()
117 .rev()
118 .find_map(|mr| {
119 mr.matched_range()
120 .map(|r| Range::new(start_range.start, r.end))
121 })
122 .unwrap_or(start_range)
123 }),
124 }
125 }
126
127 fn sort(&mut self) {
128 use core::cmp::Ordering;
129
130 self.0
131 .sort_unstable_by(|a, b| match (a.info.as_ref(), b.info.as_ref()) {
132 (None, None) => Ordering::Equal,
133 (Some(_), None) => Ordering::Less,
134 (None, Some(_)) => Ordering::Greater,
135 (Some(a), Some(b)) => a
136 .span
137 .start()
138 .cmp(&b.span.start())
139 .then_with(|| a.span.end().cmp(&b.span.end()))
140 .then_with(|| a.pattern_span.start().cmp(&b.pattern_span.start())),
141 });
142 }
143}
144impl<'input> From<MatchResult<'input>> for Matches<'input> {
145 fn from(result: MatchResult<'input>) -> Self {
146 Self(smallvec![result])
147 }
148}
149impl<'input> FromIterator<MatchResult<'input>> for Matches<'input> {
150 fn from_iter<T>(iter: T) -> Self
151 where
152 T: IntoIterator<Item = MatchResult<'input>>,
153 {
154 let mut matches = Self(SmallVec::from_iter(iter));
155 matches.sort();
156 matches
157 }
158}
159impl<'input> IntoIterator for Matches<'input> {
160 type Item = Result<Option<MatchInfo<'input>>, CheckFailedError>;
161 type IntoIter = MatchIter<'input, 1>;
162
163 #[inline]
164 fn into_iter(self) -> Self::IntoIter {
165 MatchIter::new(self.0.into_iter())
166 }
167}