use std::pin::Pin;
use std::future::Future;
use crate::fs::DirEntry;
use crate::io;
use crate::path::Path;
use crate::stream::Stream;
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned();
spawn_blocking(move || std::fs::read_dir(path))
.await
.map(ReadDir::new)
}
#[derive(Debug)]
pub struct ReadDir(State);
#[derive(Debug)]
enum State {
Idle(Option<std::fs::ReadDir>),
Busy(JoinHandle<(std::fs::ReadDir, Option<io::Result<std::fs::DirEntry>>)>),
}
impl ReadDir {
pub(crate) fn new(inner: std::fs::ReadDir) -> ReadDir {
ReadDir(State::Idle(Some(inner)))
}
}
impl Stream for ReadDir {
type Item = io::Result<DirEntry>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop {
match &mut self.0 {
State::Idle(opt) => {
let mut inner = opt.take().unwrap();
self.0 = State::Busy(spawn_blocking(move || {
let next = inner.next();
(inner, next)
}));
}
State::Busy(task) => {
let (inner, opt) = futures_core::ready!(Pin::new(task).poll(cx));
self.0 = State::Idle(Some(inner));
return Poll::Ready(opt.map(|res| res.map(DirEntry::new)));
}
}
}
}
}