#[cfg(feature = "async_std")]
pub mod async_std;
#[cfg(feature = "smol")]
pub mod smol;
#[cfg(feature = "tokio")]
pub mod tokio;
use std::{
collections::VecDeque,
env::current_dir,
fs, io,
path::{Path, PathBuf},
};
use crate::structs::target::Target;
fn is_target_exists(
path: &Path,
target: &Target,
) -> bool {
match target {
| Target::Dir(tg) => path.join(&tg.name).is_dir(),
| Target::File(tg) => path.join(&tg.name).is_file(),
}
}
pub(crate) fn is_targets_exist(
dir: &Path,
targets: &[Target],
) -> bool {
targets.iter().any(|t| is_target_exists(dir, t))
}
fn get_dir(options: GetDir) -> io::Result<PathBuf> {
let GetDir { dir, depth, targets } = options;
if depth == 0 {
return Err(io::Error::from(io::ErrorKind::NotFound));
}
let mut queue: VecDeque<(PathBuf, usize)> = VecDeque::new();
queue.push_back((dir, depth));
while let Some((current_dir, remaining_depth)) = queue.pop_front() {
if is_targets_exist(¤t_dir, &targets) {
return Ok(current_dir);
}
if remaining_depth <= 1 {
continue;
}
let entries: fs::ReadDir = match fs::read_dir(¤t_dir) {
| Ok(e) => e,
| Err(_) => continue,
};
for entry in entries.flatten() {
let path: PathBuf = entry.path();
if path.is_dir() {
queue.push_back((path, remaining_depth - 1));
}
}
}
Err(io::Error::from(io::ErrorKind::NotFound))
}
fn get_dir_reverse(options: GetDir) -> io::Result<PathBuf> {
let GetDir { dir, depth, targets } = options;
for (i, ancestor) in dir.ancestors().enumerate() {
if i >= depth {
break;
}
if is_targets_exist(ancestor, &targets) {
return Ok(ancestor.to_path_buf());
}
}
Err(io::Error::from(io::ErrorKind::NotFound))
}
#[derive(Debug, Clone)]
pub struct GetDir {
pub dir: PathBuf,
pub depth: usize,
pub targets: Vec<Target>,
}
impl GetDir {
pub fn new() -> Self {
GetDir {
dir: match current_dir() {
| Ok(path) => path,
| Err(_) => PathBuf::new(),
},
depth: usize::MAX,
targets: Vec::new(),
}
}
pub fn directory<D: Into<PathBuf>>(
mut self,
dir: D,
) -> Self {
self.dir = dir.into();
self
}
pub fn dir<D: Into<PathBuf>>(
mut self,
dir: D,
) -> Self {
self.dir = dir.into();
self
}
pub fn depth(
mut self,
depth: usize,
) -> Self {
self.depth = depth;
self
}
pub fn targets<TS, T>(
mut self,
targets: TS,
) -> Self
where
TS: IntoIterator<Item = T>,
T: Into<Target>,
{
self.targets.extend(targets.into_iter().map(|t| t.into()));
self
}
pub fn target(
mut self,
target: Target,
) -> Self {
self.targets.push(target);
self
}
pub fn run(self) -> io::Result<PathBuf> {
get_dir(self)
}
pub fn run_reverse(self) -> io::Result<PathBuf> {
get_dir_reverse(self)
}
}
impl Default for GetDir {
fn default() -> Self {
GetDir::new()
}
}