diff options
Diffstat (limited to 'src/search.rs')
-rw-r--r-- | src/search.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/search.rs b/src/search.rs new file mode 100644 index 0000000..e39d67b --- /dev/null +++ b/src/search.rs @@ -0,0 +1,129 @@ +use figment::Provider; +use std::vec::IntoIter; + +use crate::{Config, Project, Result}; + +pub use entry::Entry; + +pub mod entry; + +pub struct Search { + iter: IntoIter<entry::Config>, + curr: Option<Entry>, +} + +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> { + Self::from_provider(Config::figment()) + } + + /// Extract `Config` from `provider` to construct new `Paths` + pub fn from_provider<T: Provider>(provider: T) -> Result<Self> { + Config::extract(&provider) + .map_err(Into::into) + .map(|config| config.paths.into()) + } +} + +// impl<T> From<T> for Search +// where +// T: IntoIterator<Item = entry::Config, IntoIter = IntoIter<entry::Config>>, +// { +// fn from(value: T) -> Self { +// Self { +// iter: value.into_iter(), +// curr: None, +// } +// } +// } + +impl From<Vec<entry::Config>> for Search { + fn from(value: Vec<entry::Config>) -> Self { + Self { + iter: value.into_iter(), + curr: None, + } + } +} + +impl From<Config> for Search { + fn from(value: Config) -> Self { + value.paths.into() + } +} + +impl Iterator for Search { + type Item = Box<dyn Project>; + + #[tracing::instrument] + fn next(&mut self) -> Option<Self::Item> { + 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::Config { + path_buf: project_dir.to_owned(), + max_depth: Some(1), + ..Default::default() + }, + entry::Config { + path_buf: project3.to_owned(), + max_depth: Some(0), + ..Default::default() + }, + entry::Config { + 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::<Vec<Box<dyn Project>>>(); + results.sort_unstable_by_key(|p| p.timestamp()); + let results = results + .into_iter() + .map(|p| p.to_path_buf()) + .collect::<Vec<PathBuf>>(); + + assert_eq!(path_bufs, results); + } +} |