@@ -259,6 +259,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
259259 original : "" . to_string ( ) ,
260260 tokens : Vec :: new ( ) ,
261261 is_recursive : false ,
262+ has_metachars : false ,
262263 } ) ;
263264 }
264265
@@ -552,6 +553,9 @@ pub struct Pattern {
552553 original : String ,
553554 tokens : Vec < PatternToken > ,
554555 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 ,
555559}
556560
557561/// Show the original glob pattern.
@@ -605,15 +609,19 @@ impl Pattern {
605609 let chars = pattern. chars ( ) . collect :: < Vec < _ > > ( ) ;
606610 let mut tokens = Vec :: new ( ) ;
607611 let mut is_recursive = false ;
612+ let mut has_metachars = false ;
608613 let mut i = 0 ;
609614
610615 while i < chars. len ( ) {
611616 match chars[ i] {
612617 '?' => {
618+ has_metachars = true ;
613619 tokens. push ( AnyChar ) ;
614620 i += 1 ;
615621 }
616622 '*' => {
623+ has_metachars = true ;
624+
617625 let old = i;
618626
619627 while i < chars. len ( ) && chars[ i] == '*' {
@@ -675,6 +683,8 @@ impl Pattern {
675683 }
676684 }
677685 '[' => {
686+ has_metachars = true ;
687+
678688 if i + 4 <= chars. len ( ) && chars[ i + 1 ] == '!' {
679689 match chars[ i + 3 ..] . iter ( ) . position ( |x| * x == ']' ) {
680690 None => ( ) ,
@@ -715,6 +725,7 @@ impl Pattern {
715725 tokens,
716726 original : pattern. to_string ( ) ,
717727 is_recursive,
728+ has_metachars,
718729 } )
719730 }
720731
@@ -878,19 +889,6 @@ fn fill_todo(
878889 path : & PathWrapper ,
879890 options : MatchOptions ,
880891) {
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-
894892 let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
895893 if idx + 1 == patterns. len ( ) {
896894 // We know it's good, so don't make the iterator match this path
@@ -905,8 +903,17 @@ fn fill_todo(
905903 let pattern = & patterns[ idx] ;
906904 let is_dir = path. is_directory ;
907905 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+
910917 // This pattern component doesn't have any metacharacters, so we
911918 // don't need to read the current directory to know where to
912919 // continue. So instead of passing control back to the iterator,
@@ -916,7 +923,7 @@ fn fill_todo(
916923 let next_path = if curdir {
917924 PathBuf :: from ( s)
918925 } else {
919- path. join ( & s)
926+ path. join ( s)
920927 } ;
921928 let next_path = PathWrapper :: from_path ( next_path) ;
922929 if ( special && is_dir)
@@ -927,7 +934,7 @@ fn fill_todo(
927934 add ( todo, next_path) ;
928935 }
929936 }
930- None if is_dir => {
937+ ( true , true ) => {
931938 let dirs = fs:: read_dir ( path) . and_then ( |d| {
932939 d. map ( |e| {
933940 e. map ( |e| {
@@ -971,7 +978,7 @@ fn fill_todo(
971978 }
972979 }
973980 }
974- None => {
981+ ( true , false ) => {
975982 // not a directory, nothing more to find
976983 }
977984 }
0 commit comments