11use std:: ffi:: OsString ;
22use std:: fs;
33use std:: path:: PathBuf ;
4- use std:: pin:: Pin ;
5- use std:: sync:: Mutex ;
4+ use std:: sync:: Arc ;
65
76use cfg_if:: cfg_if;
8- use futures:: future:: { self , FutureExt , TryFutureExt } ;
97
10- use crate :: future:: Future ;
118use crate :: io;
12- use crate :: task:: { blocking, Poll } ;
9+ use crate :: task:: blocking;
1310
1411/// An entry inside a directory.
1512///
@@ -21,44 +18,25 @@ use crate::task::{blocking, Poll};
2118/// [`std::fs::DirEntry`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html
2219#[ derive( Debug ) ]
2320pub struct DirEntry {
24- /// The state of the entry.
25- state : Mutex < State > ,
26-
27- /// The full path to the entry.
28- path : PathBuf ,
21+ /// The inner synchronous `DirEntry`.
22+ inner : Arc < fs:: DirEntry > ,
2923
3024 #[ cfg( unix) ]
3125 ino : u64 ,
32-
33- /// The bare name of the entry without the leading path.
34- file_name : OsString ,
35- }
36-
37- /// The state of an asynchronous `DirEntry`.
38- ///
39- /// The `DirEntry` can be either idle or busy performing an asynchronous operation.
40- #[ derive( Debug ) ]
41- enum State {
42- Idle ( Option < fs:: DirEntry > ) ,
43- Busy ( blocking:: JoinHandle < State > ) ,
4426}
4527
4628impl DirEntry {
4729 /// Creates an asynchronous `DirEntry` from a synchronous handle.
4830 pub ( crate ) fn new ( inner : fs:: DirEntry ) -> DirEntry {
4931 #[ cfg( unix) ]
5032 let dir_entry = DirEntry {
51- path : inner. path ( ) ,
52- file_name : inner. file_name ( ) ,
5333 ino : inner. ino ( ) ,
54- state : Mutex :: new ( State :: Idle ( Some ( inner) ) ) ,
34+ inner : Arc :: new ( inner) ,
5535 } ;
5636
5737 #[ cfg( windows) ]
5838 let dir_entry = DirEntry {
59- path : inner. path ( ) ,
60- file_name : inner. file_name ( ) ,
61- state : Mutex :: new ( State :: Idle ( Some ( inner) ) ) ,
39+ inner : Arc :: new ( inner) ,
6240 } ;
6341
6442 dir_entry
@@ -89,7 +67,7 @@ impl DirEntry {
8967 /// # Ok(()) }) }
9068 /// ```
9169 pub fn path ( & self ) -> PathBuf {
92- self . path . clone ( )
70+ self . inner . path ( )
9371 }
9472
9573 /// Returns the metadata for this entry.
@@ -114,35 +92,8 @@ impl DirEntry {
11492 /// # Ok(()) }) }
11593 /// ```
11694 pub async fn metadata ( & self ) -> io:: Result < fs:: Metadata > {
117- future:: poll_fn ( |cx| {
118- let state = & mut * self . state . lock ( ) . unwrap ( ) ;
119-
120- loop {
121- match state {
122- State :: Idle ( opt) => match opt. take ( ) {
123- None => return Poll :: Ready ( None ) ,
124- Some ( inner) => {
125- let ( s, r) = futures:: channel:: oneshot:: channel ( ) ;
126-
127- // Start the operation asynchronously.
128- * state = State :: Busy ( blocking:: spawn ( async move {
129- let res = inner. metadata ( ) ;
130- let _ = s. send ( res) ;
131- State :: Idle ( Some ( inner) )
132- } ) ) ;
133-
134- return Poll :: Ready ( Some ( r) ) ;
135- }
136- } ,
137- // Poll the asynchronous operation the file is currently blocked on.
138- State :: Busy ( task) => * state = futures:: ready!( Pin :: new( task) . poll( cx) ) ,
139- }
140- }
141- } )
142- . map ( |opt| opt. ok_or_else ( || io_error ( "invalid state" ) ) )
143- . await ?
144- . map_err ( |_| io_error ( "blocking task failed" ) )
145- . await ?
95+ let inner = self . inner . clone ( ) ;
96+ blocking:: spawn ( async move { inner. metadata ( ) } ) . await
14697 }
14798
14899 /// Returns the file type for this entry.
@@ -167,35 +118,8 @@ impl DirEntry {
167118 /// # Ok(()) }) }
168119 /// ```
169120 pub async fn file_type ( & self ) -> io:: Result < fs:: FileType > {
170- future:: poll_fn ( |cx| {
171- let state = & mut * self . state . lock ( ) . unwrap ( ) ;
172-
173- loop {
174- match state {
175- State :: Idle ( opt) => match opt. take ( ) {
176- None => return Poll :: Ready ( None ) ,
177- Some ( inner) => {
178- let ( s, r) = futures:: channel:: oneshot:: channel ( ) ;
179-
180- // Start the operation asynchronously.
181- * state = State :: Busy ( blocking:: spawn ( async move {
182- let res = inner. file_type ( ) ;
183- let _ = s. send ( res) ;
184- State :: Idle ( Some ( inner) )
185- } ) ) ;
186-
187- return Poll :: Ready ( Some ( r) ) ;
188- }
189- } ,
190- // Poll the asynchronous operation the file is currently blocked on.
191- State :: Busy ( task) => * state = futures:: ready!( Pin :: new( task) . poll( cx) ) ,
192- }
193- }
194- } )
195- . map ( |opt| opt. ok_or_else ( || io_error ( "invalid state" ) ) )
196- . await ?
197- . map_err ( |_| io_error ( "blocking task failed" ) )
198- . await ?
121+ let inner = self . inner . clone ( ) ;
122+ blocking:: spawn ( async move { inner. file_type ( ) } ) . await
199123 }
200124
201125 /// Returns the bare name of this entry without the leading path.
@@ -218,15 +142,10 @@ impl DirEntry {
218142 /// # Ok(()) }) }
219143 /// ```
220144 pub fn file_name ( & self ) -> OsString {
221- self . file_name . clone ( )
145+ self . inner . file_name ( )
222146 }
223147}
224148
225- /// Creates a custom `io::Error` with an arbitrary error type.
226- fn io_error ( err : impl Into < Box < dyn std:: error:: Error + Send + Sync > > ) -> io:: Error {
227- io:: Error :: new ( io:: ErrorKind :: Other , err)
228- }
229-
230149cfg_if ! {
231150 if #[ cfg( feature = "docs" ) ] {
232151 use crate :: os:: unix:: fs:: DirEntryExt ;
0 commit comments