Skip to content

Commit

Permalink
Use wrapped error that includes path
Browse files Browse the repository at this point in the history
  • Loading branch information
jdanford committed Mar 28, 2024
1 parent 38696b9 commit e901735
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 16 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "async-walkdir"
version = "1.0.0"
version = "1.1.0"
authors = ["Ririsoft <[email protected]>"]
edition = "2021"
description = "Asynchronous directory traversal for Rust."
Expand All @@ -18,4 +18,4 @@ futures-lite = "2.1.0"
async-fs = "2.1.0"

[dev-dependencies]
tempfile = "3.9.0"
tempfile = "3.9.0"
56 changes: 56 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::{
error, fmt, io, ops::Deref, path::{Path, PathBuf}
};

/// A wrapper around [`io::Error`] that includes the associated path.
#[derive(Debug)]
pub struct Error {
path: PathBuf,
inner: io::Error,
}

impl Error {
/// Create a new [`Error`]
pub fn new(path: PathBuf, inner: io::Error) -> Self {
Error { path, inner }
}

/// Returns the path associated with this error.
pub fn path(&self) -> &Path {
&self.path
}
}

impl Deref for Error {
type Target = io::Error;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl error::Error for Error {
#[allow(deprecated)]
fn description(&self) -> &str {
self.inner.description()
}

fn cause(&self) -> Option<&dyn error::Error> {
self.source()
}

fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.inner)
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"IO error for operation on {}: {}",
self.path.display(),
self.inner
)
}
}
45 changes: 31 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
#![forbid(unsafe_code)]
#![deny(missing_docs)]

mod error;

use std::future::Future;
use std::path::{Path, PathBuf};
use std::pin::Pin;
Expand All @@ -90,8 +92,11 @@ use futures_lite::stream::{self, Stream, StreamExt};

#[doc(no_inline)]
pub use async_fs::DirEntry;
#[doc(no_inline)]
pub use std::io::Result;

pub use error::Error;

/// A specialized [`Result`] type.
pub type Result<T> = std::result::Result<T, Error>;

type BoxStream = futures_lite::stream::Boxed<Result<DirEntry>>;

Expand Down Expand Up @@ -165,9 +170,9 @@ where
State::Start((root.as_ref().to_owned(), filter)),
move |state| async move {
match state {
State::Start((root, filter)) => match read_dir(root).await {
Err(e) => Some((Err(e), State::Done)),
Ok(rd) => walk(vec![rd], filter).await,
State::Start((root, filter)) => match read_dir(&root).await {
Err(e) => Some((Err(Error::new(root, e)), State::Done)),
Ok(rd) => walk(vec![(root, rd)], filter).await,
},
State::Walk((dirs, filter)) => walk(dirs, filter).await,
State::Done => None,
Expand All @@ -179,22 +184,28 @@ where

enum State<F> {
Start((PathBuf, Option<F>)),
Walk((Vec<ReadDir>, Option<F>)),
Walk((Vec<(PathBuf, ReadDir)>, Option<F>)),
Done,
}

type UnfoldState<F> = (Result<DirEntry>, State<F>);

fn walk<F, Fut>(mut dirs: Vec<ReadDir>, filter: Option<F>) -> BoxedFut<Option<UnfoldState<F>>>
fn walk<F, Fut>(
mut dirs: Vec<(PathBuf, ReadDir)>,
filter: Option<F>,
) -> BoxedFut<Option<UnfoldState<F>>>
where
F: FnMut(DirEntry) -> Fut + Send + 'static,
Fut: Future<Output = Filtering> + Send,
{
async move {
if let Some(dir) = dirs.last_mut() {
if let Some((path, dir)) = dirs.last_mut() {
match dir.next().await {
Some(Ok(entry)) => walk_entry(entry, dirs, filter).await,
Some(Err(e)) => Some((Err(e), State::Walk((dirs, filter)))),
Some(Err(e)) => Some((
Err(Error::new(path.to_path_buf(), e)),
State::Walk((dirs, filter)),
)),
None => {
dirs.pop();
walk(dirs, filter).await
Expand All @@ -209,7 +220,7 @@ where

fn walk_entry<F, Fut>(
entry: DirEntry,
mut dirs: Vec<ReadDir>,
mut dirs: Vec<(PathBuf, ReadDir)>,
mut filter: Option<F>,
) -> BoxedFut<Option<UnfoldState<F>>>
where
Expand All @@ -218,19 +229,25 @@ where
{
async move {
match entry.file_type().await {
Err(e) => Some((Err(e), State::Walk((dirs, filter)))),
Err(e) => Some((
Err(Error::new(entry.path(), e)),
State::Walk((dirs, filter)),
)),
Ok(ft) => {
let filtering = match filter.as_mut() {
Some(filter) => filter(entry.clone()).await,
None => Filtering::Continue,
};
if ft.is_dir() {
let rd = match read_dir(entry.path()).await {
Err(e) => return Some((Err(e), State::Walk((dirs, filter)))),
let path = entry.path();
let rd = match read_dir(&path).await {
Err(e) => {
return Some((Err(Error::new(path, e)), State::Walk((dirs, filter))))
}
Ok(rd) => rd,
};
if filtering != Filtering::IgnoreDir {
dirs.push(rd);
dirs.push((path, rd));
}
}
match filtering {
Expand Down

0 comments on commit e901735

Please sign in to comment.