1use super::{IntersectionError, InvalidPattern, Pattern};
2
3#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
14pub struct Patterns(Vec<Pattern>);
15
16impl Patterns {
17 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn insert(&mut self, pattern: Pattern) -> bool {
26 if self.contains(&pattern) {
27 return false;
28 }
29 self.0.retain(|member| !pattern.contains(member));
30 let at = self.0.partition_point(|member| member < &pattern);
31 self.0.insert(at, pattern);
32 true
33 }
34
35 pub fn matches(&self, path: &str) -> bool {
37 self.0.iter().any(|member| member.matches(path))
38 }
39
40 pub fn contains(&self, pattern: &Pattern) -> bool {
43 self.0.iter().any(|member| member.contains(pattern))
44 }
45
46 pub fn covers(&self, other: &Self) -> bool {
49 other.0.iter().all(|pattern| self.contains(pattern))
50 }
51
52 pub fn overlaps(&self, pattern: &Pattern) -> bool {
54 self.0.iter().any(|member| member.overlaps(pattern))
55 }
56
57 pub fn intersect(&self, other: &Self) -> Result<Self, IntersectionError> {
60 let mut out = Self::new();
61 for member in &self.0 {
62 for candidate in &other.0 {
63 for pattern in member.intersect(candidate)? {
64 out.insert(pattern);
65 if out.len() > Pattern::MAX_INTERSECTIONS {
66 return Err(IntersectionError::TooManyPatterns);
67 }
68 }
69 }
70 }
71 Ok(out)
72 }
73
74 pub fn rebase(&self, root: &str) -> Self {
76 self.0.iter().flat_map(|member| member.rebase(root)).collect()
77 }
78
79 pub fn rooted(&self, root: &str) -> Result<Self, InvalidPattern> {
81 self.0.iter().map(|member| member.rooted(root)).collect()
82 }
83
84 pub fn iter(&self) -> std::slice::Iter<'_, Pattern> {
86 self.0.iter()
87 }
88
89 pub fn len(&self) -> usize {
91 self.0.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.0.is_empty()
97 }
98}
99
100#[cfg(feature = "serde")]
101impl serde::Serialize for Patterns {
102 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
103 serializer.collect_seq(self.iter())
104 }
105}
106
107#[cfg(feature = "serde")]
108impl<'de> serde::Deserialize<'de> for Patterns {
109 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
111 Ok(Vec::<Pattern>::deserialize(deserializer)?.into_iter().collect())
112 }
113}
114
115impl std::ops::Deref for Patterns {
116 type Target = [Pattern];
117
118 fn deref(&self) -> &[Pattern] {
119 &self.0
120 }
121}
122
123impl From<Pattern> for Patterns {
124 fn from(pattern: Pattern) -> Self {
125 Self(vec![pattern])
126 }
127}
128
129impl FromIterator<Pattern> for Patterns {
130 fn from_iter<I: IntoIterator<Item = Pattern>>(iter: I) -> Self {
131 let mut set = Self::new();
132 set.extend(iter);
133 set
134 }
135}
136
137impl Extend<Pattern> for Patterns {
138 fn extend<I: IntoIterator<Item = Pattern>>(&mut self, iter: I) {
139 for pattern in iter {
140 self.insert(pattern);
141 }
142 }
143}
144
145impl IntoIterator for Patterns {
146 type Item = Pattern;
147 type IntoIter = std::vec::IntoIter<Pattern>;
148
149 fn into_iter(self) -> Self::IntoIter {
150 self.0.into_iter()
151 }
152}
153
154impl<'a> IntoIterator for &'a Patterns {
155 type Item = &'a Pattern;
156 type IntoIter = std::slice::Iter<'a, Pattern>;
157
158 fn into_iter(self) -> Self::IntoIter {
159 self.0.iter()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 fn pattern(text: &str) -> Pattern {
168 text.parse().unwrap()
169 }
170
171 fn patterns(texts: &[&str]) -> Patterns {
172 texts.iter().map(|t| pattern(t)).collect()
173 }
174
175 #[test]
176 fn insert_reduces_by_containment() {
177 let mut set = Patterns::new();
178 assert!(set.insert(pattern("a/b")));
179 assert!(set.insert(pattern("a/c")));
180 assert!(!set.insert(pattern("a/b")));
181 assert!(set.insert(pattern("a/*")));
182 assert_eq!(set, patterns(&["a/*"]));
183 assert!(!set.insert(pattern("a/d")));
184 assert!(set.insert(pattern("**/x")));
185 assert_eq!(set.len(), 2);
186 assert!(set.insert(pattern("**")));
187 assert_eq!(set, patterns(&["**"]));
188 }
189
190 #[test]
191 fn equality_is_set_equality() {
192 assert_eq!(patterns(&["a", "b"]), patterns(&["b", "a"]));
193 assert_eq!(patterns(&["a", "a/**", "b"]), patterns(&["b", "a/**"]));
194 assert_ne!(patterns(&["a"]), patterns(&["a", "b"]));
195 }
196
197 #[test]
198 fn joint_coverage_is_not_containment() {
199 let set = patterns(&["a", "a/*", "a/*/**"]);
200 assert!(!set.contains(&pattern("a/**")));
201 assert!(set.contains(&pattern("a/x/**")));
202 assert!(set.covers(&patterns(&["a", "a/x/y"])));
203 assert!(!set.covers(&patterns(&["a", "b"])));
204 assert!(set.covers(&Patterns::new()));
205 assert!(!Patterns::new().covers(&set));
206 }
207
208 #[test]
209 fn matches_and_overlaps_any_member() {
210 let set = patterns(&["a/**", "**/c"]);
211 assert!(set.matches("a"));
212 assert!(set.matches("x/c"));
213 assert!(!set.matches("x/y"));
214 assert!(set.overlaps(&pattern("*/c")));
215 assert!(!set.overlaps(&pattern("b/d")));
216 assert!(!Patterns::new().matches(""));
217 }
218
219 #[cfg(feature = "serde")]
220 #[test]
221 fn serde_round_trips_reduced() {
222 let set: Patterns = serde_json::from_str(r#"["a/b", "a/*", "**/c"]"#).unwrap();
223 assert_eq!(serde_json::to_string(&set).unwrap(), r#"["**/c","a/*"]"#);
224 }
225
226 #[test]
227 fn intersect_is_pairwise() {
228 let grant = patterns(&["a/*", "b/**"]);
229 let claim = patterns(&["*/c", "b/d/**"]);
230 assert_eq!(grant.intersect(&claim).unwrap(), patterns(&["a/c", "b/c", "b/d/**"]));
231 assert!(grant.intersect(&patterns(&["x"])).unwrap().is_empty());
232 assert!(Patterns::new().intersect(&grant).unwrap().is_empty());
233 }
234
235 #[test]
236 fn rebase_and_rooted_round_trip() {
237 let set = patterns(&["**/a", "b/**"]);
238 assert_eq!(set.rebase("a"), patterns(&["", "**/a"]));
239 assert_eq!(set.rebase("b/c"), patterns(&["**"]));
240 assert_eq!(set.rebase("x"), patterns(&["**/a"]));
241 assert_eq!(set.rooted("r").unwrap(), patterns(&["r/**/a", "r/b/**"]));
242 assert!(set.rooted("*").is_err());
243 }
244}