1use crate::errors::{Error, ErrorKind};
2use std::ffi::OsString;
3use std::fs::{FileType, Metadata};
4use std::io;
5use std::path::{Path, PathBuf};
6use std::task::{ready, Context, Poll};
7use tokio::fs;
8
9#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
13pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
14 let path = path.as_ref();
15 let tokio = fs::read_dir(path)
16 .await
17 .map_err(|err| Error::build(err, ErrorKind::ReadDir, path))?;
18 Ok(ReadDir {
19 tokio,
20 path: path.to_owned(),
21 })
22}
23
24#[derive(Debug)]
28#[must_use = "streams do nothing unless polled"]
29#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
30pub struct ReadDir {
31 tokio: fs::ReadDir,
32 path: PathBuf,
33}
34
35impl ReadDir {
36 pub async fn next_entry(&mut self) -> io::Result<Option<DirEntry>> {
40 match self.tokio.next_entry().await {
41 Ok(entry) => Ok(entry.map(|e| DirEntry { tokio: e })),
42 Err(err) => Err(Error::build(err, ErrorKind::ReadDir, &self.path)),
43 }
44 }
45
46 pub fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Option<DirEntry>>> {
50 Poll::Ready(match ready!(self.tokio.poll_next_entry(cx)) {
51 Ok(entry) => Ok(entry.map(|e| DirEntry { tokio: e })),
52 Err(err) => Err(Error::build(err, ErrorKind::ReadDir, &self.path)),
53 })
54 }
55}
56
57#[derive(Debug)]
61#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
62pub struct DirEntry {
63 tokio: fs::DirEntry,
64}
65
66impl DirEntry {
67 pub fn path(&self) -> PathBuf {
71 self.tokio.path()
72 }
73
74 pub fn file_name(&self) -> OsString {
79 self.tokio.file_name()
80 }
81
82 pub async fn metadata(&self) -> io::Result<Metadata> {
86 self.tokio
87 .metadata()
88 .await
89 .map_err(|err| Error::build(err, ErrorKind::Metadata, self.path()))
90 }
91
92 pub async fn file_type(&self) -> io::Result<FileType> {
96 self.tokio
97 .file_type()
98 .await
99 .map_err(|err| Error::build(err, ErrorKind::Metadata, self.path()))
100 }
101}
102
103#[cfg(unix)]
104impl DirEntry {
105 pub fn ino(&self) -> u64 {
109 self.tokio.ino()
110 }
111}