use figment::Provider; use std::vec::IntoIter; use self::entry::EntryIter; use crate::{config::Entry, project::ProjectItem, Config, Result}; pub mod entry; pub struct Search { iter: IntoIter, curr: Option, } impl std::fmt::Debug for Search { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Projects") .field("paths_iter", &self.iter) .finish_non_exhaustive() } } impl Search { pub fn new() -> Result { Self::from_provider(Config::figment()) } /// Extract `Config` from `provider` to construct new `Paths` pub fn from_provider(provider: T) -> Result { Config::extract(&provider) .map_err(Into::into) .map(|config| config.paths.into()) } } impl From for Search { fn from(config: Config) -> Self { config.paths.into() } } impl From for Search where T: IntoIterator>, { fn from(value: T) -> Self { Self { iter: value.into_iter(), curr: None, } } } impl Iterator for Search { type Item = ProjectItem; #[tracing::instrument] fn next(&mut self) -> Option { match self.curr.as_mut().and_then(|c| c.next()) { Some(proj) => Some(proj), None => { self.curr = Some(self.iter.next()?.into()); self.next() } } } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; use std::{fs, path::PathBuf}; #[test] fn test_iteration() { let temp_dir = tempfile::Builder::new() .tempdir() .unwrap() .path() .to_owned(); let project_dir = temp_dir.join("project_dir"); let project1 = temp_dir.join("project_dir/project1"); let project2 = temp_dir.join("project_dir/project2"); let project3 = temp_dir.join("project3"); let project4 = temp_dir.join("subdir/project4"); let paths = Search::from(Vec::from([ Entry { path_buf: project_dir.to_owned(), max_depth: Some(1), ..Default::default() }, Entry { path_buf: project3.to_owned(), max_depth: Some(0), ..Default::default() }, Entry { path_buf: project4.to_owned(), max_depth: Some(0), ..Default::default() }, ])); let mut path_bufs = Vec::from([project_dir, project1, project2, project3, project4]); path_bufs.iter().try_for_each(fs::create_dir_all).unwrap(); path_bufs.sort(); let mut results = paths.into_iter().collect::>(); results.sort_unstable_by_key(|p| *p.timestamp()); let results = results .into_iter() .map(|p| p.to_path_buf().to_owned()) .collect::>(); assert_eq!(path_bufs, results); } }