@@ -73,7 +73,9 @@ use std::cmp;
7373use std:: error:: Error ;
7474use std:: fmt;
7575use std:: fs;
76+ use std:: fs:: DirEntry ;
7677use std:: io;
78+ use std:: ops:: Deref ;
7779use std:: path:: { self , Component , Path , PathBuf } ;
7880use std:: str:: FromStr ;
7981
@@ -96,8 +98,8 @@ pub struct Paths {
9698 dir_patterns : Vec < Pattern > ,
9799 require_dir : bool ,
98100 options : MatchOptions ,
99- todo : Vec < Result < ( PathBuf , usize ) , GlobError > > ,
100- scope : Option < PathBuf > ,
101+ todo : Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
102+ scope : Option < PathWrapper > ,
101103}
102104
103105/// Return an iterator that produces all the `Path`s that match the given
@@ -242,6 +244,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
242244 }
243245
244246 let scope = root. map_or_else ( || PathBuf :: from ( "." ) , to_scope) ;
247+ let scope = PathWrapper :: from_path ( scope) ;
245248
246249 let mut dir_patterns = Vec :: new ( ) ;
247250 let components =
@@ -323,8 +326,44 @@ impl fmt::Display for GlobError {
323326 }
324327}
325328
326- fn is_dir ( p : & Path ) -> bool {
327- fs:: metadata ( p) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false )
329+ #[ derive( Debug ) ]
330+ struct PathWrapper {
331+ path : PathBuf ,
332+ is_directory : bool ,
333+ }
334+
335+ impl PathWrapper {
336+ fn from_dir_entry ( path : PathBuf , e : DirEntry ) -> Self {
337+ let is_directory = e
338+ . file_type ( )
339+ . ok ( )
340+ . map ( |file_type| file_type. is_dir ( ) )
341+ . or_else ( || fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . ok ( ) )
342+ . unwrap_or ( false ) ;
343+ Self { path, is_directory }
344+ }
345+ fn from_path ( path : PathBuf ) -> Self {
346+ let is_directory = fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false ) ;
347+ Self { path, is_directory }
348+ }
349+
350+ fn into_path ( self ) -> PathBuf {
351+ self . path
352+ }
353+ }
354+
355+ impl Deref for PathWrapper {
356+ type Target = Path ;
357+
358+ fn deref ( & self ) -> & Self :: Target {
359+ self . path . deref ( )
360+ }
361+ }
362+
363+ impl AsRef < Path > for PathWrapper {
364+ fn as_ref ( & self ) -> & Path {
365+ self . path . as_ref ( )
366+ }
328367}
329368
330369/// An alias for a glob iteration result.
@@ -363,10 +402,10 @@ impl Iterator for Paths {
363402 // idx -1: was already checked by fill_todo, maybe path was '.' or
364403 // '..' that we can't match here because of normalization.
365404 if idx == !0 as usize {
366- if self . require_dir && !is_dir ( & path) {
405+ if self . require_dir && !path. is_directory {
367406 continue ;
368407 }
369- return Some ( Ok ( path) ) ;
408+ return Some ( Ok ( path. into_path ( ) ) ) ;
370409 }
371410
372411 if self . dir_patterns [ idx] . is_recursive {
@@ -379,7 +418,7 @@ impl Iterator for Paths {
379418 next += 1 ;
380419 }
381420
382- if is_dir ( & path) {
421+ if path. is_directory {
383422 // the path is a directory, so it's a match
384423
385424 // push this directory's contents
@@ -394,7 +433,7 @@ impl Iterator for Paths {
394433 if next == self . dir_patterns . len ( ) - 1 {
395434 // pattern ends in recursive pattern, so return this
396435 // directory as a result
397- return Some ( Ok ( path) ) ;
436+ return Some ( Ok ( path. into_path ( ) ) ) ;
398437 } else {
399438 // advanced to the next pattern for this path
400439 idx = next + 1 ;
@@ -427,8 +466,8 @@ impl Iterator for Paths {
427466 // *AND* its children so we don't need to check the
428467 // children
429468
430- if !self . require_dir || is_dir ( & path) {
431- return Some ( Ok ( path) ) ;
469+ if !self . require_dir || path. is_directory {
470+ return Some ( Ok ( path. into_path ( ) ) ) ;
432471 }
433472 } else {
434473 fill_todo (
@@ -817,10 +856,10 @@ impl Pattern {
817856// special-casing patterns to match `.` and `..`, and avoiding `readdir()`
818857// calls when there are no metacharacters in the pattern.
819858fn fill_todo (
820- todo : & mut Vec < Result < ( PathBuf , usize ) , GlobError > > ,
859+ todo : & mut Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
821860 patterns : & [ Pattern ] ,
822861 idx : usize ,
823- path : & Path ,
862+ path : & PathWrapper ,
824863 options : MatchOptions ,
825864) {
826865 // convert a pattern that's just many Char(_) to a string
@@ -836,7 +875,7 @@ fn fill_todo(
836875 Some ( s)
837876 }
838877
839- let add = |todo : & mut Vec < _ > , next_path : PathBuf | {
878+ let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
840879 if idx + 1 == patterns. len ( ) {
841880 // We know it's good, so don't make the iterator match this path
842881 // against the pattern again. In particular, it can't match
@@ -848,8 +887,8 @@ fn fill_todo(
848887 } ;
849888
850889 let pattern = & patterns[ idx] ;
851- let is_dir = is_dir ( path) ;
852- let curdir = path == Path :: new ( "." ) ;
890+ let is_dir = path. is_directory ;
891+ let curdir = path. as_ref ( ) == Path :: new ( "." ) ;
853892 match pattern_as_str ( pattern) {
854893 Some ( s) => {
855894 // This pattern component doesn't have any metacharacters, so we
@@ -863,6 +902,7 @@ fn fill_todo(
863902 } else {
864903 path. join ( & s)
865904 } ;
905+ let next_path = PathWrapper :: from_path ( next_path) ;
866906 if ( special && is_dir)
867907 || ( !special
868908 && ( fs:: metadata ( & next_path) . is_ok ( )
@@ -875,19 +915,21 @@ fn fill_todo(
875915 let dirs = fs:: read_dir ( path) . and_then ( |d| {
876916 d. map ( |e| {
877917 e. map ( |e| {
878- if curdir {
918+ let path = if curdir {
879919 PathBuf :: from ( e. path ( ) . file_name ( ) . unwrap ( ) )
880920 } else {
881921 e. path ( )
882- }
922+ } ;
923+ PathWrapper :: from_dir_entry ( path, e)
883924 } )
884925 } )
885926 . collect :: < Result < Vec < _ > , _ > > ( )
886927 } ) ;
887928 match dirs {
888929 Ok ( mut children) => {
889930 if options. require_literal_leading_dot {
890- children. retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
931+ children
932+ . retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
891933 }
892934 children. sort_by ( |p1, p2| p2. file_name ( ) . cmp ( & p1. file_name ( ) ) ) ;
893935 todo. extend ( children. into_iter ( ) . map ( |x| Ok ( ( x, idx) ) ) ) ;
@@ -900,7 +942,7 @@ fn fill_todo(
900942 if !pattern. tokens . is_empty ( ) && pattern. tokens [ 0 ] == Char ( '.' ) {
901943 for & special in & [ "." , ".." ] {
902944 if pattern. matches_with ( special, options) {
903- add ( todo, path. join ( special) ) ;
945+ add ( todo, PathWrapper :: from_path ( path. join ( special) ) ) ;
904946 }
905947 }
906948 }
0 commit comments