1
1
use std:: ffi:: OsString ;
2
2
use std:: fs;
3
3
use std:: path:: PathBuf ;
4
- use std:: pin:: Pin ;
5
- use std:: sync:: Mutex ;
4
+ use std:: sync:: Arc ;
6
5
7
6
use cfg_if:: cfg_if;
8
- use futures:: future:: { self , FutureExt , TryFutureExt } ;
9
7
10
- use crate :: future:: Future ;
11
8
use crate :: io;
12
- use crate :: task:: { blocking, Poll } ;
9
+ use crate :: task:: blocking;
13
10
14
11
/// An entry inside a directory.
15
12
///
@@ -21,44 +18,25 @@ use crate::task::{blocking, Poll};
21
18
/// [`std::fs::DirEntry`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html
22
19
#[ derive( Debug ) ]
23
20
pub 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 > ,
29
23
30
24
#[ cfg( unix) ]
31
25
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 > ) ,
44
26
}
45
27
46
28
impl DirEntry {
47
29
/// Creates an asynchronous `DirEntry` from a synchronous handle.
48
30
pub ( crate ) fn new ( inner : fs:: DirEntry ) -> DirEntry {
49
31
#[ cfg( unix) ]
50
32
let dir_entry = DirEntry {
51
- path : inner. path ( ) ,
52
- file_name : inner. file_name ( ) ,
53
33
ino : inner. ino ( ) ,
54
- state : Mutex :: new ( State :: Idle ( Some ( inner) ) ) ,
34
+ inner : Arc :: new ( inner) ,
55
35
} ;
56
36
57
37
#[ cfg( windows) ]
58
38
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) ,
62
40
} ;
63
41
64
42
dir_entry
@@ -89,7 +67,7 @@ impl DirEntry {
89
67
/// # Ok(()) }) }
90
68
/// ```
91
69
pub fn path ( & self ) -> PathBuf {
92
- self . path . clone ( )
70
+ self . inner . path ( )
93
71
}
94
72
95
73
/// Returns the metadata for this entry.
@@ -114,35 +92,8 @@ impl DirEntry {
114
92
/// # Ok(()) }) }
115
93
/// ```
116
94
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
146
97
}
147
98
148
99
/// Returns the file type for this entry.
@@ -167,35 +118,8 @@ impl DirEntry {
167
118
/// # Ok(()) }) }
168
119
/// ```
169
120
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
199
123
}
200
124
201
125
/// Returns the bare name of this entry without the leading path.
@@ -218,15 +142,10 @@ impl DirEntry {
218
142
/// # Ok(()) }) }
219
143
/// ```
220
144
pub fn file_name ( & self ) -> OsString {
221
- self . file_name . clone ( )
145
+ self . inner . file_name ( )
222
146
}
223
147
}
224
148
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
-
230
149
cfg_if ! {
231
150
if #[ cfg( feature = "docs" ) ] {
232
151
use crate :: os:: unix:: fs:: DirEntryExt ;
0 commit comments