use super::FileSource;
use crate::Result;
use ignore::{Walk, WalkBuilder};
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
pub struct Directory {
buf_size: usize,
walk_builder: WalkBuilder,
}
pub struct Iter {
walk: Walk,
}
impl Directory {
pub fn new(path: impl AsRef<Path>, buf_size: usize) -> Result<Self> {
let path = path.as_ref();
if !path.is_dir() {
return Err("path is not a directory".into());
}
let walk_builder = WalkBuilder::new(path);
let directory = Self {
buf_size,
walk_builder,
};
Ok(directory)
}
}
impl<'files> FileSource<'files> for Directory {
type Entry = PathBuf;
type Filepath = PathBuf;
type Contents = Vec<u8>;
type State = ();
type Iter = Iter;
fn entries(&'files self) -> crate::Result<Self::Iter> {
let walk = self.walk_builder.build();
Ok(Iter { walk })
}
fn filepath(
&'files self,
entry: &Self::Entry,
_state: &mut Self::State,
) -> crate::Result<Self::Filepath> {
Ok(entry.to_owned())
}
fn contents(
&'files self,
entry: &Self::Entry,
_state: &mut Self::State,
) -> crate::Result<Self::Contents> {
let mut reader = File::open(entry)?.take(self.buf_size.try_into()?);
let mut buf = vec![0; self.buf_size];
let read_amount = reader.read(&mut buf)?;
buf.resize(read_amount, 0);
Ok(buf)
}
fn state(&'files self) -> crate::Result<Self::State> {
Ok(())
}
}
impl Iterator for Iter {
type Item = PathBuf;
fn next(&mut self) -> Option<Self::Item> {
self.walk
.next()
.and_then(|entry| entry.ok())
.map(|dir_entry| dir_entry.path().to_owned())
}
}