1
+ use std:: cell:: RefCell ;
1
2
use std:: fs:: File ;
2
3
use std:: fs:: OpenOptions ;
3
4
use std:: io:: { ErrorKind , Read , Write } ;
@@ -10,9 +11,11 @@ use crate::obj::objbytes::PyBytesRef;
10
11
use crate :: obj:: objdict:: PyDictRef ;
11
12
use crate :: obj:: objint;
12
13
use crate :: obj:: objint:: PyIntRef ;
14
+ use crate :: obj:: objiter;
13
15
use crate :: obj:: objstr;
14
16
use crate :: obj:: objstr:: PyStringRef ;
15
- use crate :: pyobject:: { ItemProtocol , PyObjectRef , PyResult } ;
17
+ use crate :: obj:: objtype:: PyClassRef ;
18
+ use crate :: pyobject:: { ItemProtocol , PyObjectRef , PyRef , PyResult , PyValue } ;
16
19
use crate :: vm:: VirtualMachine ;
17
20
18
21
#[ cfg( unix) ]
@@ -190,6 +193,85 @@ fn _os_environ(vm: &VirtualMachine) -> PyDictRef {
190
193
environ
191
194
}
192
195
196
+ #[ derive( Debug ) ]
197
+ struct DirEntry {
198
+ entry : fs:: DirEntry ,
199
+ }
200
+
201
+ type DirEntryRef = PyRef < DirEntry > ;
202
+
203
+ impl PyValue for DirEntry {
204
+ fn class ( vm : & VirtualMachine ) -> PyClassRef {
205
+ vm. class ( "os" , "DirEntry" )
206
+ }
207
+ }
208
+
209
+ impl DirEntryRef {
210
+ fn name ( self , _vm : & VirtualMachine ) -> String {
211
+ self . entry . file_name ( ) . into_string ( ) . unwrap ( )
212
+ }
213
+
214
+ fn path ( self , _vm : & VirtualMachine ) -> String {
215
+ self . entry . path ( ) . to_str ( ) . unwrap ( ) . to_string ( )
216
+ }
217
+
218
+ fn is_dir ( self , vm : & VirtualMachine ) -> PyResult < bool > {
219
+ Ok ( self
220
+ . entry
221
+ . file_type ( )
222
+ . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) ) ?
223
+ . is_dir ( ) )
224
+ }
225
+
226
+ fn is_file ( self , vm : & VirtualMachine ) -> PyResult < bool > {
227
+ Ok ( self
228
+ . entry
229
+ . file_type ( )
230
+ . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) ) ?
231
+ . is_file ( ) )
232
+ }
233
+ }
234
+
235
+ #[ derive( Debug ) ]
236
+ pub struct ScandirIterator {
237
+ entries : RefCell < fs:: ReadDir > ,
238
+ }
239
+
240
+ impl PyValue for ScandirIterator {
241
+ fn class ( vm : & VirtualMachine ) -> PyClassRef {
242
+ vm. class ( "os" , "ScandirIter" )
243
+ }
244
+ }
245
+
246
+ type ScandirIteratorRef = PyRef < ScandirIterator > ;
247
+
248
+ impl ScandirIteratorRef {
249
+ fn next ( self , vm : & VirtualMachine ) -> PyResult {
250
+ match self . entries . borrow_mut ( ) . next ( ) {
251
+ Some ( entry) => match entry {
252
+ Ok ( entry) => Ok ( DirEntry { entry } . into_ref ( vm) . into_object ( ) ) ,
253
+ Err ( s) => Err ( vm. new_os_error ( s. to_string ( ) ) ) ,
254
+ } ,
255
+ None => Err ( objiter:: new_stop_iteration ( vm) ) ,
256
+ }
257
+ }
258
+
259
+ fn iter ( self , _vm : & VirtualMachine ) -> Self {
260
+ self
261
+ }
262
+ }
263
+
264
+ fn os_scandir ( path : PyStringRef , vm : & VirtualMachine ) -> PyResult {
265
+ match fs:: read_dir ( & path. value ) {
266
+ Ok ( iter) => Ok ( ScandirIterator {
267
+ entries : RefCell :: new ( iter) ,
268
+ }
269
+ . into_ref ( vm)
270
+ . into_object ( ) ) ,
271
+ Err ( s) => Err ( vm. new_os_error ( s. to_string ( ) ) ) ,
272
+ }
273
+ }
274
+
193
275
pub fn make_module ( vm : & VirtualMachine ) -> PyObjectRef {
194
276
let ctx = & vm. ctx ;
195
277
@@ -201,6 +283,18 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
201
283
202
284
let environ = _os_environ ( vm) ;
203
285
286
+ let scandir_iter = py_class ! ( ctx, "ScandirIter" , ctx. object( ) , {
287
+ "__iter__" => ctx. new_rustfunc( ScandirIteratorRef :: iter) ,
288
+ "__next__" => ctx. new_rustfunc( ScandirIteratorRef :: next) ,
289
+ } ) ;
290
+
291
+ let dir_entry = py_class ! ( ctx, "DirEntry" , ctx. object( ) , {
292
+ "name" => ctx. new_property( DirEntryRef :: name) ,
293
+ "path" => ctx. new_property( DirEntryRef :: path) ,
294
+ "is_dir" => ctx. new_rustfunc( DirEntryRef :: is_dir) ,
295
+ "is_file" => ctx. new_rustfunc( DirEntryRef :: is_file) ,
296
+ } ) ;
297
+
204
298
py_module ! ( vm, "_os" , {
205
299
"open" => ctx. new_rustfunc( os_open) ,
206
300
"close" => ctx. new_rustfunc( os_close) ,
@@ -217,6 +311,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
217
311
"unsetenv" => ctx. new_rustfunc( os_unsetenv) ,
218
312
"environ" => environ,
219
313
"name" => ctx. new_str( os_name) ,
314
+ "scandir" => ctx. new_rustfunc( os_scandir) ,
315
+ "ScandirIter" => scandir_iter,
316
+ "DirEntry" => dir_entry,
220
317
"O_RDONLY" => ctx. new_int( 0 ) ,
221
318
"O_WRONLY" => ctx. new_int( 1 ) ,
222
319
"O_RDWR" => ctx. new_int( 2 ) ,
0 commit comments