Show More
@@ -368,6 +368,87 b' impl UnionMatcher {' | |||||
368 | } |
|
368 | } | |
369 | } |
|
369 | } | |
370 |
|
370 | |||
|
371 | pub struct IntersectionMatcher { | |||
|
372 | m1: Box<dyn Matcher + Sync>, | |||
|
373 | m2: Box<dyn Matcher + Sync>, | |||
|
374 | files: Option<HashSet<HgPathBuf>>, | |||
|
375 | } | |||
|
376 | ||||
|
377 | impl Matcher for IntersectionMatcher { | |||
|
378 | fn file_set(&self) -> Option<&HashSet<HgPathBuf>> { | |||
|
379 | self.files.as_ref() | |||
|
380 | } | |||
|
381 | ||||
|
382 | fn exact_match(&self, filename: &HgPath) -> bool { | |||
|
383 | self.files.as_ref().map_or(false, |f| f.contains(filename)) | |||
|
384 | } | |||
|
385 | ||||
|
386 | fn matches(&self, filename: &HgPath) -> bool { | |||
|
387 | self.m1.matches(filename) && self.m2.matches(filename) | |||
|
388 | } | |||
|
389 | ||||
|
390 | fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet { | |||
|
391 | let m1_set = self.m1.visit_children_set(directory); | |||
|
392 | if m1_set == VisitChildrenSet::Empty { | |||
|
393 | return VisitChildrenSet::Empty; | |||
|
394 | } | |||
|
395 | let m2_set = self.m2.visit_children_set(directory); | |||
|
396 | if m2_set == VisitChildrenSet::Empty { | |||
|
397 | return VisitChildrenSet::Empty; | |||
|
398 | } | |||
|
399 | ||||
|
400 | if m1_set == VisitChildrenSet::Recursive { | |||
|
401 | return m2_set; | |||
|
402 | } else if m2_set == VisitChildrenSet::Recursive { | |||
|
403 | return m1_set; | |||
|
404 | } | |||
|
405 | ||||
|
406 | match (&m1_set, &m2_set) { | |||
|
407 | (VisitChildrenSet::Recursive, _) => m2_set, | |||
|
408 | (_, VisitChildrenSet::Recursive) => m1_set, | |||
|
409 | (VisitChildrenSet::This, _) | (_, VisitChildrenSet::This) => { | |||
|
410 | VisitChildrenSet::This | |||
|
411 | } | |||
|
412 | (VisitChildrenSet::Set(m1), VisitChildrenSet::Set(m2)) => { | |||
|
413 | let set: HashSet<_> = m1.intersection(&m2).cloned().collect(); | |||
|
414 | if set.is_empty() { | |||
|
415 | VisitChildrenSet::Empty | |||
|
416 | } else { | |||
|
417 | VisitChildrenSet::Set(set) | |||
|
418 | } | |||
|
419 | } | |||
|
420 | _ => unreachable!(), | |||
|
421 | } | |||
|
422 | } | |||
|
423 | ||||
|
424 | fn matches_everything(&self) -> bool { | |||
|
425 | self.m1.matches_everything() && self.m2.matches_everything() | |||
|
426 | } | |||
|
427 | ||||
|
428 | fn is_exact(&self) -> bool { | |||
|
429 | self.m1.is_exact() || self.m2.is_exact() | |||
|
430 | } | |||
|
431 | } | |||
|
432 | ||||
|
433 | impl IntersectionMatcher { | |||
|
434 | pub fn new( | |||
|
435 | mut m1: Box<dyn Matcher + Sync>, | |||
|
436 | mut m2: Box<dyn Matcher + Sync>, | |||
|
437 | ) -> Self { | |||
|
438 | let files = if m1.is_exact() || m2.is_exact() { | |||
|
439 | if !m1.is_exact() { | |||
|
440 | std::mem::swap(&mut m1, &mut m2); | |||
|
441 | } | |||
|
442 | m1.file_set().map(|m1_files| { | |||
|
443 | m1_files.iter().cloned().filter(|f| m2.matches(f)).collect() | |||
|
444 | }) | |||
|
445 | } else { | |||
|
446 | None | |||
|
447 | }; | |||
|
448 | Self { m1, m2, files } | |||
|
449 | } | |||
|
450 | } | |||
|
451 | ||||
371 | /// Returns a function that matches an `HgPath` against the given regex |
|
452 | /// Returns a function that matches an `HgPath` against the given regex | |
372 | /// pattern. |
|
453 | /// pattern. | |
373 | /// |
|
454 | /// | |
@@ -1147,4 +1228,215 b' mod tests {' | |||||
1147 | VisitChildrenSet::This |
|
1228 | VisitChildrenSet::This | |
1148 | ); |
|
1229 | ); | |
1149 | } |
|
1230 | } | |
|
1231 | ||||
|
1232 | #[test] | |||
|
1233 | fn test_intersectionmatcher() { | |||
|
1234 | // Include path + Include rootfiles | |||
|
1235 | let m1 = Box::new( | |||
|
1236 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1237 | PatternSyntax::RelPath, | |||
|
1238 | b"dir/subdir", | |||
|
1239 | Path::new(""), | |||
|
1240 | )]) | |||
|
1241 | .unwrap(), | |||
|
1242 | ); | |||
|
1243 | let m2 = Box::new( | |||
|
1244 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1245 | PatternSyntax::RootFiles, | |||
|
1246 | b"dir", | |||
|
1247 | Path::new(""), | |||
|
1248 | )]) | |||
|
1249 | .unwrap(), | |||
|
1250 | ); | |||
|
1251 | let matcher = IntersectionMatcher::new(m1, m2); | |||
|
1252 | ||||
|
1253 | let mut set = HashSet::new(); | |||
|
1254 | set.insert(HgPathBuf::from_bytes(b"dir")); | |||
|
1255 | assert_eq!( | |||
|
1256 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
1257 | VisitChildrenSet::Set(set) | |||
|
1258 | ); | |||
|
1259 | assert_eq!( | |||
|
1260 | matcher.visit_children_set(HgPath::new(b"dir")), | |||
|
1261 | VisitChildrenSet::This | |||
|
1262 | ); | |||
|
1263 | assert_eq!( | |||
|
1264 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |||
|
1265 | VisitChildrenSet::Empty | |||
|
1266 | ); | |||
|
1267 | assert_eq!( | |||
|
1268 | matcher.visit_children_set(HgPath::new(b"dir/foo")), | |||
|
1269 | VisitChildrenSet::Empty | |||
|
1270 | ); | |||
|
1271 | assert_eq!( | |||
|
1272 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
1273 | VisitChildrenSet::Empty | |||
|
1274 | ); | |||
|
1275 | assert_eq!( | |||
|
1276 | matcher.visit_children_set(HgPath::new(b"dir/subdir/z")), | |||
|
1277 | VisitChildrenSet::Empty | |||
|
1278 | ); | |||
|
1279 | assert_eq!( | |||
|
1280 | matcher.visit_children_set(HgPath::new(b"dir/subdir/x")), | |||
|
1281 | VisitChildrenSet::Empty | |||
|
1282 | ); | |||
|
1283 | ||||
|
1284 | // Non intersecting paths | |||
|
1285 | let m1 = Box::new( | |||
|
1286 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1287 | PatternSyntax::RelPath, | |||
|
1288 | b"dir/subdir", | |||
|
1289 | Path::new(""), | |||
|
1290 | )]) | |||
|
1291 | .unwrap(), | |||
|
1292 | ); | |||
|
1293 | let m2 = Box::new( | |||
|
1294 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1295 | PatternSyntax::RelPath, | |||
|
1296 | b"folder", | |||
|
1297 | Path::new(""), | |||
|
1298 | )]) | |||
|
1299 | .unwrap(), | |||
|
1300 | ); | |||
|
1301 | let matcher = IntersectionMatcher::new(m1, m2); | |||
|
1302 | ||||
|
1303 | assert_eq!( | |||
|
1304 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
1305 | VisitChildrenSet::Empty | |||
|
1306 | ); | |||
|
1307 | assert_eq!( | |||
|
1308 | matcher.visit_children_set(HgPath::new(b"dir")), | |||
|
1309 | VisitChildrenSet::Empty | |||
|
1310 | ); | |||
|
1311 | assert_eq!( | |||
|
1312 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |||
|
1313 | VisitChildrenSet::Empty | |||
|
1314 | ); | |||
|
1315 | assert_eq!( | |||
|
1316 | matcher.visit_children_set(HgPath::new(b"dir/foo")), | |||
|
1317 | VisitChildrenSet::Empty | |||
|
1318 | ); | |||
|
1319 | assert_eq!( | |||
|
1320 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
1321 | VisitChildrenSet::Empty | |||
|
1322 | ); | |||
|
1323 | assert_eq!( | |||
|
1324 | matcher.visit_children_set(HgPath::new(b"dir/subdir/z")), | |||
|
1325 | VisitChildrenSet::Empty | |||
|
1326 | ); | |||
|
1327 | assert_eq!( | |||
|
1328 | matcher.visit_children_set(HgPath::new(b"dir/subdir/x")), | |||
|
1329 | VisitChildrenSet::Empty | |||
|
1330 | ); | |||
|
1331 | ||||
|
1332 | // Nested paths | |||
|
1333 | let m1 = Box::new( | |||
|
1334 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1335 | PatternSyntax::RelPath, | |||
|
1336 | b"dir/subdir/x", | |||
|
1337 | Path::new(""), | |||
|
1338 | )]) | |||
|
1339 | .unwrap(), | |||
|
1340 | ); | |||
|
1341 | let m2 = Box::new( | |||
|
1342 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1343 | PatternSyntax::RelPath, | |||
|
1344 | b"dir/subdir", | |||
|
1345 | Path::new(""), | |||
|
1346 | )]) | |||
|
1347 | .unwrap(), | |||
|
1348 | ); | |||
|
1349 | let matcher = IntersectionMatcher::new(m1, m2); | |||
|
1350 | ||||
|
1351 | let mut set = HashSet::new(); | |||
|
1352 | set.insert(HgPathBuf::from_bytes(b"dir")); | |||
|
1353 | assert_eq!( | |||
|
1354 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
1355 | VisitChildrenSet::Set(set) | |||
|
1356 | ); | |||
|
1357 | ||||
|
1358 | let mut set = HashSet::new(); | |||
|
1359 | set.insert(HgPathBuf::from_bytes(b"subdir")); | |||
|
1360 | assert_eq!( | |||
|
1361 | matcher.visit_children_set(HgPath::new(b"dir")), | |||
|
1362 | VisitChildrenSet::Set(set) | |||
|
1363 | ); | |||
|
1364 | let mut set = HashSet::new(); | |||
|
1365 | set.insert(HgPathBuf::from_bytes(b"x")); | |||
|
1366 | assert_eq!( | |||
|
1367 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |||
|
1368 | VisitChildrenSet::Set(set) | |||
|
1369 | ); | |||
|
1370 | assert_eq!( | |||
|
1371 | matcher.visit_children_set(HgPath::new(b"dir/foo")), | |||
|
1372 | VisitChildrenSet::Empty | |||
|
1373 | ); | |||
|
1374 | assert_eq!( | |||
|
1375 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
1376 | VisitChildrenSet::Empty | |||
|
1377 | ); | |||
|
1378 | assert_eq!( | |||
|
1379 | matcher.visit_children_set(HgPath::new(b"dir/subdir/z")), | |||
|
1380 | VisitChildrenSet::Empty | |||
|
1381 | ); | |||
|
1382 | // OPT: this should probably be 'all' not 'this'. | |||
|
1383 | assert_eq!( | |||
|
1384 | matcher.visit_children_set(HgPath::new(b"dir/subdir/x")), | |||
|
1385 | VisitChildrenSet::This | |||
|
1386 | ); | |||
|
1387 | ||||
|
1388 | // Diverging paths | |||
|
1389 | let m1 = Box::new( | |||
|
1390 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1391 | PatternSyntax::RelPath, | |||
|
1392 | b"dir/subdir/x", | |||
|
1393 | Path::new(""), | |||
|
1394 | )]) | |||
|
1395 | .unwrap(), | |||
|
1396 | ); | |||
|
1397 | let m2 = Box::new( | |||
|
1398 | IncludeMatcher::new(vec![IgnorePattern::new( | |||
|
1399 | PatternSyntax::RelPath, | |||
|
1400 | b"dir/subdir/z", | |||
|
1401 | Path::new(""), | |||
|
1402 | )]) | |||
|
1403 | .unwrap(), | |||
|
1404 | ); | |||
|
1405 | let matcher = IntersectionMatcher::new(m1, m2); | |||
|
1406 | ||||
|
1407 | // OPT: these next two could probably be Empty as well. | |||
|
1408 | let mut set = HashSet::new(); | |||
|
1409 | set.insert(HgPathBuf::from_bytes(b"dir")); | |||
|
1410 | assert_eq!( | |||
|
1411 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
1412 | VisitChildrenSet::Set(set) | |||
|
1413 | ); | |||
|
1414 | // OPT: these next two could probably be Empty as well. | |||
|
1415 | let mut set = HashSet::new(); | |||
|
1416 | set.insert(HgPathBuf::from_bytes(b"subdir")); | |||
|
1417 | assert_eq!( | |||
|
1418 | matcher.visit_children_set(HgPath::new(b"dir")), | |||
|
1419 | VisitChildrenSet::Set(set) | |||
|
1420 | ); | |||
|
1421 | assert_eq!( | |||
|
1422 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |||
|
1423 | VisitChildrenSet::Empty | |||
|
1424 | ); | |||
|
1425 | assert_eq!( | |||
|
1426 | matcher.visit_children_set(HgPath::new(b"dir/foo")), | |||
|
1427 | VisitChildrenSet::Empty | |||
|
1428 | ); | |||
|
1429 | assert_eq!( | |||
|
1430 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
1431 | VisitChildrenSet::Empty | |||
|
1432 | ); | |||
|
1433 | assert_eq!( | |||
|
1434 | matcher.visit_children_set(HgPath::new(b"dir/subdir/z")), | |||
|
1435 | VisitChildrenSet::Empty | |||
|
1436 | ); | |||
|
1437 | assert_eq!( | |||
|
1438 | matcher.visit_children_set(HgPath::new(b"dir/subdir/x")), | |||
|
1439 | VisitChildrenSet::Empty | |||
|
1440 | ); | |||
|
1441 | } | |||
1150 | } |
|
1442 | } |
General Comments 0
You need to be logged in to leave comments.
Login now