@@ -166,6 +166,8 @@ impl Matcher for PrefixMatcher {
166
166
}
167
167
}
168
168
169
+ /// Matches paths that are matched by the first input matcher but not by the
170
+ /// second.
169
171
pub struct DifferenceMatcher < ' input > {
170
172
/// The minuend
171
173
wanted : & ' input dyn Matcher ,
@@ -199,6 +201,70 @@ impl Matcher for DifferenceMatcher<'_> {
199
201
}
200
202
}
201
203
204
+ /// Matches paths that are matched by both input matchers.
205
+ pub struct IntersectionMatcher < ' input > {
206
+ input1 : & ' input dyn Matcher ,
207
+ input2 : & ' input dyn Matcher ,
208
+ }
209
+
210
+ impl < ' input > IntersectionMatcher < ' input > {
211
+ pub fn new ( input1 : & ' input dyn Matcher , input2 : & ' input dyn Matcher ) -> Self {
212
+ Self { input1, input2 }
213
+ }
214
+ }
215
+
216
+ impl Matcher for IntersectionMatcher < ' _ > {
217
+ fn matches ( & self , file : & RepoPath ) -> bool {
218
+ self . input1 . matches ( file) && self . input2 . matches ( file)
219
+ }
220
+
221
+ fn visit ( & self , dir : & RepoPath ) -> Visit {
222
+ match self . input1 . visit ( dir) {
223
+ Visit :: AllRecursively => self . input2 . visit ( dir) ,
224
+ Visit :: Nothing => Visit :: Nothing ,
225
+ Visit :: Specific {
226
+ dirs : dirs1,
227
+ files : files1,
228
+ } => match self . input2 . visit ( dir) {
229
+ Visit :: AllRecursively => Visit :: Specific {
230
+ dirs : dirs1,
231
+ files : files1,
232
+ } ,
233
+ Visit :: Nothing => Visit :: Nothing ,
234
+ Visit :: Specific {
235
+ dirs : dirs2,
236
+ files : files2,
237
+ } => {
238
+ let dirs = match ( dirs1, dirs2) {
239
+ ( VisitDirs :: All , VisitDirs :: All ) => VisitDirs :: All ,
240
+ ( dirs1, VisitDirs :: All ) => dirs1,
241
+ ( VisitDirs :: All , dirs2) => dirs2,
242
+ ( VisitDirs :: Set ( dirs1) , VisitDirs :: Set ( dirs2) ) => {
243
+ VisitDirs :: Set ( dirs1. intersection ( & dirs2) . cloned ( ) . collect ( ) )
244
+ }
245
+ } ;
246
+ let files = match ( files1, files2) {
247
+ ( VisitFiles :: All , VisitFiles :: All ) => VisitFiles :: All ,
248
+ ( files1, VisitFiles :: All ) => files1,
249
+ ( VisitFiles :: All , files2) => files2,
250
+ ( VisitFiles :: Set ( files1) , VisitFiles :: Set ( files2) ) => {
251
+ VisitFiles :: Set ( files1. intersection ( & files2) . cloned ( ) . collect ( ) )
252
+ }
253
+ } ;
254
+ match ( & dirs, & files) {
255
+ ( VisitDirs :: Set ( dirs) , VisitFiles :: Set ( files) )
256
+ if dirs. is_empty ( ) && files. is_empty ( ) =>
257
+ {
258
+ Visit :: Nothing
259
+ }
260
+ _ => Visit :: Specific { dirs, files } ,
261
+ }
262
+ }
263
+ } ,
264
+ }
265
+ }
266
+ }
267
+
202
268
/// Keeps track of which subdirectories and files of each directory need to be
203
269
/// visited.
204
270
#[ derive( PartialEq , Eq , Debug ) ]
@@ -530,4 +596,89 @@ mod tests {
530
596
Visit :: AllRecursively
531
597
) ;
532
598
}
599
+
600
+ #[ test]
601
+ fn test_intersectionmatcher_intersecting_roots ( ) {
602
+ let m1 = PrefixMatcher :: new ( & [
603
+ RepoPath :: from_internal_string ( "foo" ) ,
604
+ RepoPath :: from_internal_string ( "bar" ) ,
605
+ ] ) ;
606
+ let m2 = PrefixMatcher :: new ( & [
607
+ RepoPath :: from_internal_string ( "bar" ) ,
608
+ RepoPath :: from_internal_string ( "baz" ) ,
609
+ ] ) ;
610
+ let m = IntersectionMatcher :: new ( & m1, & m2) ;
611
+
612
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "foo" ) ) ) ;
613
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "foo/bar" ) ) ) ;
614
+ assert ! ( m. matches( & RepoPath :: from_internal_string( "bar" ) ) ) ;
615
+ assert ! ( m. matches( & RepoPath :: from_internal_string( "bar/foo" ) ) ) ;
616
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "baz" ) ) ) ;
617
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "baz/foo" ) ) ) ;
618
+
619
+ assert_eq ! (
620
+ m. visit( & RepoPath :: root( ) ) ,
621
+ Visit :: sets(
622
+ hashset! { RepoPathComponent :: from( "bar" ) } ,
623
+ hashset! { RepoPathComponent :: from( "bar" ) }
624
+ )
625
+ ) ;
626
+ assert_eq ! (
627
+ m. visit( & RepoPath :: from_internal_string( "foo" ) ) ,
628
+ Visit :: Nothing
629
+ ) ;
630
+ assert_eq ! (
631
+ m. visit( & RepoPath :: from_internal_string( "foo/bar" ) ) ,
632
+ Visit :: Nothing
633
+ ) ;
634
+ assert_eq ! (
635
+ m. visit( & RepoPath :: from_internal_string( "bar" ) ) ,
636
+ Visit :: AllRecursively
637
+ ) ;
638
+ assert_eq ! (
639
+ m. visit( & RepoPath :: from_internal_string( "bar/foo" ) ) ,
640
+ Visit :: AllRecursively
641
+ ) ;
642
+ assert_eq ! (
643
+ m. visit( & RepoPath :: from_internal_string( "baz" ) ) ,
644
+ Visit :: Nothing
645
+ ) ;
646
+ assert_eq ! (
647
+ m. visit( & RepoPath :: from_internal_string( "baz/foo" ) ) ,
648
+ Visit :: Nothing
649
+ ) ;
650
+ }
651
+
652
+ #[ test]
653
+ fn test_intersectionmatcher_subdir ( ) {
654
+ let m1 = PrefixMatcher :: new ( & [ RepoPath :: from_internal_string ( "foo" ) ] ) ;
655
+ let m2 = PrefixMatcher :: new ( & [ RepoPath :: from_internal_string ( "foo/bar" ) ] ) ;
656
+ let m = IntersectionMatcher :: new ( & m1, & m2) ;
657
+
658
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "foo" ) ) ) ;
659
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "bar" ) ) ) ;
660
+ assert ! ( m. matches( & RepoPath :: from_internal_string( "foo/bar" ) ) ) ;
661
+ assert ! ( m. matches( & RepoPath :: from_internal_string( "foo/bar/baz" ) ) ) ;
662
+ assert ! ( !m. matches( & RepoPath :: from_internal_string( "foo/baz" ) ) ) ;
663
+
664
+ assert_eq ! (
665
+ m. visit( & RepoPath :: root( ) ) ,
666
+ Visit :: sets( hashset! { RepoPathComponent :: from( "foo" ) } , hashset! { } )
667
+ ) ;
668
+ assert_eq ! (
669
+ m. visit( & RepoPath :: from_internal_string( "bar" ) ) ,
670
+ Visit :: Nothing
671
+ ) ;
672
+ assert_eq ! (
673
+ m. visit( & RepoPath :: from_internal_string( "foo" ) ) ,
674
+ Visit :: sets(
675
+ hashset! { RepoPathComponent :: from( "bar" ) } ,
676
+ hashset! { RepoPathComponent :: from( "bar" ) }
677
+ )
678
+ ) ;
679
+ assert_eq ! (
680
+ m. visit( & RepoPath :: from_internal_string( "foo/bar" ) ) ,
681
+ Visit :: AllRecursively
682
+ ) ;
683
+ }
533
684
}
0 commit comments