@@ -259,6 +259,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
259
259
original : "" . to_string ( ) ,
260
260
tokens : Vec :: new ( ) ,
261
261
is_recursive : false ,
262
+ has_metachars : false ,
262
263
} ) ;
263
264
}
264
265
@@ -552,6 +553,9 @@ pub struct Pattern {
552
553
original : String ,
553
554
tokens : Vec < PatternToken > ,
554
555
is_recursive : bool ,
556
+ /// A bool value that indicates whether the pattern contains any metacharacters.
557
+ /// We use this information for some fast path optimizations.
558
+ has_metachars : bool ,
555
559
}
556
560
557
561
/// Show the original glob pattern.
@@ -605,15 +609,19 @@ impl Pattern {
605
609
let chars = pattern. chars ( ) . collect :: < Vec < _ > > ( ) ;
606
610
let mut tokens = Vec :: new ( ) ;
607
611
let mut is_recursive = false ;
612
+ let mut has_metachars = false ;
608
613
let mut i = 0 ;
609
614
610
615
while i < chars. len ( ) {
611
616
match chars[ i] {
612
617
'?' => {
618
+ has_metachars = true ;
613
619
tokens. push ( AnyChar ) ;
614
620
i += 1 ;
615
621
}
616
622
'*' => {
623
+ has_metachars = true ;
624
+
617
625
let old = i;
618
626
619
627
while i < chars. len ( ) && chars[ i] == '*' {
@@ -675,6 +683,8 @@ impl Pattern {
675
683
}
676
684
}
677
685
'[' => {
686
+ has_metachars = true ;
687
+
678
688
if i + 4 <= chars. len ( ) && chars[ i + 1 ] == '!' {
679
689
match chars[ i + 3 ..] . iter ( ) . position ( |x| * x == ']' ) {
680
690
None => ( ) ,
@@ -715,6 +725,7 @@ impl Pattern {
715
725
tokens,
716
726
original : pattern. to_string ( ) ,
717
727
is_recursive,
728
+ has_metachars,
718
729
} )
719
730
}
720
731
@@ -878,19 +889,6 @@ fn fill_todo(
878
889
path : & PathWrapper ,
879
890
options : MatchOptions ,
880
891
) {
881
- // convert a pattern that's just many Char(_) to a string
882
- fn pattern_as_str ( pattern : & Pattern ) -> Option < String > {
883
- let mut s = String :: new ( ) ;
884
- for token in & pattern. tokens {
885
- match * token {
886
- Char ( c) => s. push ( c) ,
887
- _ => return None ,
888
- }
889
- }
890
-
891
- Some ( s)
892
- }
893
-
894
892
let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
895
893
if idx + 1 == patterns. len ( ) {
896
894
// We know it's good, so don't make the iterator match this path
@@ -905,8 +903,17 @@ fn fill_todo(
905
903
let pattern = & patterns[ idx] ;
906
904
let is_dir = path. is_directory ;
907
905
let curdir = path. as_ref ( ) == Path :: new ( "." ) ;
908
- match pattern_as_str ( pattern) {
909
- Some ( s) => {
906
+ match ( pattern. has_metachars , is_dir) {
907
+ ( false , _) => {
908
+ debug_assert ! (
909
+ pattern
910
+ . tokens
911
+ . iter( )
912
+ . all( |tok| matches!( tok, PatternToken :: Char ( _) ) ) ,
913
+ "broken invariant: pattern has metachars but shouldn't"
914
+ ) ;
915
+ let s = pattern. as_str ( ) ;
916
+
910
917
// This pattern component doesn't have any metacharacters, so we
911
918
// don't need to read the current directory to know where to
912
919
// continue. So instead of passing control back to the iterator,
@@ -916,7 +923,7 @@ fn fill_todo(
916
923
let next_path = if curdir {
917
924
PathBuf :: from ( s)
918
925
} else {
919
- path. join ( & s)
926
+ path. join ( s)
920
927
} ;
921
928
let next_path = PathWrapper :: from_path ( next_path) ;
922
929
if ( special && is_dir)
@@ -927,7 +934,7 @@ fn fill_todo(
927
934
add ( todo, next_path) ;
928
935
}
929
936
}
930
- None if is_dir => {
937
+ ( true , true ) => {
931
938
let dirs = fs:: read_dir ( path) . and_then ( |d| {
932
939
d. map ( |e| {
933
940
e. map ( |e| {
@@ -971,7 +978,7 @@ fn fill_todo(
971
978
}
972
979
}
973
980
}
974
- None => {
981
+ ( true , false ) => {
975
982
// not a directory, nothing more to find
976
983
}
977
984
}
0 commit comments