use std::path::Path;
use std::path::PathBuf;
use crate::raw::*;
use crate::EntryMode;
use crate::Metadata;
use crate::Result;
pub struct FsLister<P> {
root: PathBuf,
current_path: Option<String>,
rd: P,
}
impl<P> FsLister<P> {
pub fn new(root: &Path, path: &str, rd: P) -> Self {
Self {
root: root.to_owned(),
current_path: Some(path.to_string()),
rd,
}
}
}
unsafe impl<P> Sync for FsLister<P> {}
impl oio::List for FsLister<tokio::fs::ReadDir> {
async fn next(&mut self) -> Result<Option<oio::Entry>> {
if let Some(path) = self.current_path.take() {
let e = oio::Entry::new(path.as_str(), Metadata::new(EntryMode::DIR));
return Ok(Some(e));
}
let Some(de) = self.rd.next_entry().await.map_err(new_std_io_error)? else {
return Ok(None);
};
let entry_path = de.path();
let rel_path = normalize_path(
&entry_path
.strip_prefix(&self.root)
.expect("cannot fail because the prefix is iterated")
.to_string_lossy()
.replace('\\', "/"),
);
let ft = de.file_type().await.map_err(new_std_io_error)?;
let entry = if ft.is_dir() {
oio::Entry::new(&format!("{rel_path}/"), Metadata::new(EntryMode::DIR))
} else if ft.is_file() {
oio::Entry::new(&rel_path, Metadata::new(EntryMode::FILE))
} else {
oio::Entry::new(&rel_path, Metadata::new(EntryMode::Unknown))
};
Ok(Some(entry))
}
}
impl oio::BlockingList for FsLister<std::fs::ReadDir> {
fn next(&mut self) -> Result<Option<oio::Entry>> {
if let Some(path) = self.current_path.take() {
let e = oio::Entry::new(path.as_str(), Metadata::new(EntryMode::DIR));
return Ok(Some(e));
}
let de = match self.rd.next() {
Some(de) => de.map_err(new_std_io_error)?,
None => return Ok(None),
};
let entry_path = de.path();
let rel_path = normalize_path(
&entry_path
.strip_prefix(&self.root)
.expect("cannot fail because the prefix is iterated")
.to_string_lossy()
.replace('\\', "/"),
);
let ft = de.file_type().map_err(new_std_io_error)?;
let entry = if ft.is_dir() {
oio::Entry::new(&format!("{rel_path}/"), Metadata::new(EntryMode::DIR))
} else if ft.is_file() {
oio::Entry::new(&rel_path, Metadata::new(EntryMode::FILE))
} else {
oio::Entry::new(&rel_path, Metadata::new(EntryMode::Unknown))
};
Ok(Some(entry))
}
}