use std::{
ffi::OsString,
fmt,
future::Future,
io,
path::{Path, PathBuf},
pin::Pin,
sync::Arc,
task::{Context, Poll, ready},
};
use futures_core::Stream;
use super::{FileType, Metadata, sealed::Sealed};
use crate::{Unblock, unblock};
pub struct ReadDir(Unblock<std::fs::ReadDir>);
impl ReadDir {
pub(super) fn new(dir: std::fs::ReadDir) -> Self {
Self(Unblock::new(dir))
}
}
impl Stream for ReadDir {
type Item = io::Result<DirEntry>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let entry = ready!(Pin::new(&mut self.0).poll_next(cx));
Poll::Ready(entry.map(|entry| entry.map(|entry| DirEntry(Arc::new(entry)))))
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadDir").finish_non_exhaustive()
}
}
#[derive(Clone)]
pub struct DirEntry(Arc<std::fs::DirEntry>);
impl DirEntry {
pub fn path(&self) -> PathBuf {
self.0.path()
}
pub fn file_name(&self) -> OsString {
self.0.file_name()
}
pub async fn metadata(&self) -> io::Result<Metadata> {
let entry = self.0.clone();
unblock(move || entry.metadata()).await
}
pub async fn file_type(&self) -> io::Result<FileType> {
let entry = self.0.clone();
unblock(move || entry.file_type()).await
}
}
impl fmt::Debug for DirEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
impl Sealed for DirEntry {}
#[cfg(unix)]
impl super::unix::DirEntryExt for DirEntry {
fn ino(&self) -> u64 {
std::os::unix::fs::DirEntryExt::ino(&*self.0)
}
}
#[derive(Debug, Default)]
pub struct DirBuilder {
recursive: bool,
#[cfg(unix)]
mode: Option<u32>,
}
impl DirBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
self.recursive = recursive;
self
}
pub fn create<P>(&self, path: P) -> impl Future<Output = io::Result<()>> + use<P>
where
P: AsRef<Path>,
{
let builder = self.to_std();
let path = path.as_ref().to_owned();
async move { unblock(move || builder.create(path)).await }
}
fn to_std(&self) -> std::fs::DirBuilder {
let mut builder = std::fs::DirBuilder::new();
builder.recursive(self.recursive);
#[cfg(unix)]
if let Some(mode) = self.mode {
std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
}
builder
}
}
impl Sealed for DirBuilder {}
#[cfg(unix)]
impl super::unix::DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);
self
}
}