@@ -53,6 +53,47 @@ pub struct ReadDir {
5353 first : Option < c:: WIN32_FIND_DATAW > ,
5454}
5555
56+ /// Specialization trait used to construct a `ReadDir`
57+ trait ReadDirFromPath < P > {
58+ fn from_path (
59+ handle : Option < FindNextFileHandle > ,
60+ path : P ,
61+ first : Option < c:: WIN32_FIND_DATAW > ,
62+ ) -> Self ;
63+ }
64+
65+ impl < P : AsRef < Path > > ReadDirFromPath < P > for ReadDir {
66+ default fn from_path (
67+ handle : Option < FindNextFileHandle > ,
68+ path : P ,
69+ first : Option < c:: WIN32_FIND_DATAW > ,
70+ ) -> Self {
71+ ReadDir { handle, root : Arc :: new ( path. as_ref ( ) . to_path_buf ( ) ) , first }
72+ }
73+ }
74+
75+ /// This constructs a `ReadDir` for all types that can be converted
76+ /// into `PathBuf` without allocating
77+ macro_rules! impl_read_dir_from_path {
78+ ( $t: ty) => {
79+ impl ReadDirFromPath <$t> for ReadDir {
80+ fn from_path(
81+ handle: Option <FindNextFileHandle >,
82+ path: $t,
83+ first: Option <c:: WIN32_FIND_DATAW >,
84+ ) -> Self {
85+ ReadDir { handle, root: Arc :: new( path. into( ) ) , first }
86+ }
87+ }
88+ } ;
89+ }
90+
91+ impl_read_dir_from_path ! ( PathBuf ) ;
92+ impl_read_dir_from_path ! ( Box <Path >) ;
93+ impl_read_dir_from_path ! ( Cow <' _, Path >) ;
94+ impl_read_dir_from_path ! ( OsString ) ;
95+ impl_read_dir_from_path ! ( String ) ;
96+
5697struct FindNextFileHandle ( c:: HANDLE ) ;
5798
5899unsafe impl Send for FindNextFileHandle { }
@@ -1222,17 +1263,16 @@ impl DirBuilder {
12221263 }
12231264}
12241265
1225- pub fn readdir ( p : & Path ) -> io:: Result < ReadDir > {
1266+ pub fn readdir < P : AsRef < Path > > ( p : P ) -> io:: Result < ReadDir > {
12261267 // We push a `*` to the end of the path which cause the empty path to be
12271268 // treated as the current directory. So, for consistency with other platforms,
12281269 // we explicitly error on the empty path.
1229- if p. as_os_str ( ) . is_empty ( ) {
1270+ if p. as_ref ( ) . as_os_str ( ) . is_empty ( ) {
12301271 // Return an error code consistent with other ways of opening files.
12311272 // E.g. fs::metadata or File::open.
12321273 return Err ( io:: Error :: from_raw_os_error ( c:: ERROR_PATH_NOT_FOUND as i32 ) ) ;
12331274 }
1234- let root = p. to_path_buf ( ) ;
1235- let star = p. join ( "*" ) ;
1275+ let star = p. as_ref ( ) . join ( "*" ) ;
12361276 let path = maybe_verbatim ( & star) ?;
12371277
12381278 unsafe {
@@ -1254,11 +1294,11 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
12541294 ) ;
12551295
12561296 if find_handle != c:: INVALID_HANDLE_VALUE {
1257- Ok ( ReadDir {
1258- handle : Some ( FindNextFileHandle ( find_handle) ) ,
1259- root : Arc :: new ( root ) ,
1260- first : Some ( wfd) ,
1261- } )
1297+ Ok ( < ReadDir as ReadDirFromPath < P > > :: from_path (
1298+ Some ( FindNextFileHandle ( find_handle) ) ,
1299+ p ,
1300+ Some ( wfd) ,
1301+ ) )
12621302 } else {
12631303 // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileExW` function
12641304 // if no matching files can be found, but not necessarily that the path to find the
@@ -1273,7 +1313,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
12731313 // See issue #120040: https://github.com/rust-lang/rust/issues/120040.
12741314 let last_error = api:: get_last_error ( ) ;
12751315 if last_error == WinError :: FILE_NOT_FOUND {
1276- return Ok ( ReadDir { handle : None , root : Arc :: new ( root ) , first : None } ) ;
1316+ return Ok ( < ReadDir as ReadDirFromPath < P > > :: from_path ( None , p , None ) ) ;
12771317 }
12781318
12791319 // Just return the error constructed from the raw OS error if the above is not the case.
0 commit comments