Skip to content

Commit 3828652

Browse files
committed
Add os.scandir
1 parent 3afb5d3 commit 3828652

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

vm/src/stdlib/os.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cell::RefCell;
12
use std::fs::File;
23
use std::fs::OpenOptions;
34
use std::io::{ErrorKind, Read, Write};
@@ -10,9 +11,11 @@ use crate::obj::objbytes::PyBytesRef;
1011
use crate::obj::objdict::PyDictRef;
1112
use crate::obj::objint;
1213
use crate::obj::objint::PyIntRef;
14+
use crate::obj::objiter;
1315
use crate::obj::objstr;
1416
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};
1619
use crate::vm::VirtualMachine;
1720

1821
#[cfg(unix)]
@@ -190,6 +193,65 @@ fn _os_environ(vm: &VirtualMachine) -> PyDictRef {
190193
environ
191194
}
192195

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+
215+
#[derive(Debug)]
216+
pub struct ScandirIterator {
217+
entries: RefCell<fs::ReadDir>,
218+
}
219+
220+
impl PyValue for ScandirIterator {
221+
fn class(vm: &VirtualMachine) -> PyClassRef {
222+
vm.class("os", "ScandirIter")
223+
}
224+
}
225+
226+
type ScandirIteratorRef = PyRef<ScandirIterator>;
227+
228+
impl ScandirIteratorRef {
229+
fn next(self, vm: &VirtualMachine) -> PyResult {
230+
match self.entries.borrow_mut().next() {
231+
Some(entry) => match entry {
232+
Ok(entry) => Ok(DirEntry { entry }.into_ref(vm).into_object()),
233+
Err(s) => Err(vm.new_os_error(s.to_string())),
234+
},
235+
None => Err(objiter::new_stop_iteration(vm)),
236+
}
237+
}
238+
239+
fn iter(self, _vm: &VirtualMachine) -> Self {
240+
self
241+
}
242+
}
243+
244+
fn os_scandir(path: PyStringRef, vm: &VirtualMachine) -> PyResult {
245+
match fs::read_dir(&path.value) {
246+
Ok(iter) => Ok(ScandirIterator {
247+
entries: RefCell::new(iter),
248+
}
249+
.into_ref(vm)
250+
.into_object()),
251+
Err(s) => Err(vm.new_os_error(s.to_string())),
252+
}
253+
}
254+
193255
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
194256
let ctx = &vm.ctx;
195257

@@ -201,6 +263,15 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
201263

202264
let environ = _os_environ(vm);
203265

266+
let scandir_iter = py_class!(ctx, "ScandirIter", ctx.object(), {
267+
"__iter__" => ctx.new_rustfunc(ScandirIteratorRef::iter),
268+
"__next__" => ctx.new_rustfunc(ScandirIteratorRef::next),
269+
});
270+
271+
let dir_entry = py_class!(ctx, "DirEntry", ctx.object(), {
272+
"name" => ctx.new_rustfunc(DirEntryRef::name),
273+
});
274+
204275
py_module!(vm, "_os", {
205276
"open" => ctx.new_rustfunc(os_open),
206277
"close" => ctx.new_rustfunc(os_close),
@@ -217,6 +288,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
217288
"unsetenv" => ctx.new_rustfunc(os_unsetenv),
218289
"environ" => environ,
219290
"name" => ctx.new_str(os_name),
291+
"scandir" => ctx.new_rustfunc(os_scandir),
292+
"ScandirIter" => scandir_iter,
293+
"DirEntry" => dir_entry,
220294
"O_RDONLY" => ctx.new_int(0),
221295
"O_WRONLY" => ctx.new_int(1),
222296
"O_RDWR" => ctx.new_int(2),

0 commit comments

Comments
 (0)