diff --git a/TODO.md b/TODO.md index 85c51f0..c08c6db 100644 --- a/TODO.md +++ b/TODO.md @@ -1,2 +1,4 @@ -TODO: Support -R - Non-blind recursion (like sxiv-ordered) -NOTE: Nesting BTreeSet is probably not the best way to go about this... +# TODO: Support -R - Non-blind recursion (like sxiv-ordered) + +## Requires +A mpsc channel refactor to support sending parents... diff --git a/src/main.rs b/src/main.rs index ae4c13d..dce7949 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,20 @@ async fn work_on(cfg: work::Config, mut into: mpsc::Receiver) -> Ok(map) } +async fn work_on_tree(cfg: work::Config, mut into: mpsc::Receiver<(Option, work::FileInfo)>) -> eyre::Result +{ + //TODO: How to refactor the mpsc channel to support this and the blind (above) version??? + use work::*; + let mut map = NestedFsTreeMap::new(cfg); + while let Some((parent, file)) = into.recv().await { + if cfg!(debug_assertions) { + trace!("insert {:?}/ +{}", parent, map.len()); + } + map.insert(parent, file); + } + Ok(map) +} + async fn walk_paths(paths: I, cfg: walk::Config, worker_cfg: &std::sync::Arc, to: mpsc::Sender) -> eyre::Result where I: futures::stream::Stream, P: AsRef diff --git a/src/work.rs b/src/work.rs index aee3f50..b5a120b 100644 --- a/src/work.rs +++ b/src/work.rs @@ -33,6 +33,7 @@ pub struct FileInfo state: Arc, //TODO: XXX: This will be a *severe* slowdown... How can we have just a reference here? Thread local? `tokio::task_local!`? Global static? path: PathBuf, meta: Metadata, + dir: bool, } impl FileInfo @@ -53,6 +54,7 @@ impl FileInfo { Self { state: config.into(), + dir: meta.is_dir(), path, meta } } @@ -122,6 +124,46 @@ impl order::Orderer for FileInfo #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct FSTimeMap(Arc, BTreeSet>); +/// Maps files based on their time maintaining directory structure. +/// +/// # Note +/// The output of this ordering is still a flat-map. Children are corrently grouped beneath their parents. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct NestedFsTreeMap(Arc, BTreeSet>); + +impl NestedFsTreeMap +{ + #[inline] + pub fn new(config: impl Into) -> Self + { + Self (Arc::new(config.into()), BTreeSet::new()) + } + + #[inline] + pub fn iter(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator + std::iter::FusedIterator + '_ + { + self.1.iter().map(|x| &x.inner().file) + } + + #[inline] + pub fn into_iter(self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator + std::iter::FusedIterator + 'static + { + self.1.into_iter().map(|x| x.into_inner().file) + } + + #[inline] + pub fn insert(&mut self, parent: impl Into>, file: FileInfo) + { + self.1.insert(order::Ordered::new(NestedFileInfo::new(parent.into(), file))); + } + + #[inline] + pub fn len(&self) -> usize + { + self.1.len() + } +} + impl FSTimeMap { #[inline] @@ -154,3 +196,72 @@ impl FSTimeMap self.1.len() } } + +/// Tree-maintaining file info +#[derive(Debug, Clone)] +pub struct NestedFileInfo +{ + file: FileInfo, + parent: Option +} + +impl NestedFileInfo +{ + #[inline] + pub fn new(parent: Option, file: FileInfo) -> Self + { + Self { + file, + parent, + } + } + + #[inline] + pub fn into_inner(self) -> FileInfo + { + self.file + } + + #[inline] + pub fn parent(&self) -> Option<&FileInfo> + { + self.parent.as_ref() + } +} + +impl order::Orderer for FileInfo +{ + #[inline] + fn order(a: &NestedFileInfo, b: &NestedFileInfo) -> std::cmp::Ordering { + + if let Some(parent) = &a.parent { + // Check if `b` is parent of `a`, if so, `a` *always* comes after `b` + if parent.path() == b.file.path() { + return std::cmp::Ordering::Greater; + } + + // If `a`'s parent is not the same as `b`'s parent, then `a` always comes *before* `b`. + if let Some(bparent) = &b.parent { + if !FileInfo::order(parent, bparent).is_eq() { + return std::cmp::Ordering::Less; + } + } + } + + if let Some(parent) = &b.parent { + // Check if `a` is parent of `b`, if so, `b` *always* comes after `a`. + if parent.path() == a.file.path() { + return std::cmp::Ordering::Less; + } + + // If `b`'s parent is not the same as `a`'s parent, then `b` always comes *before* `a`. + if let Some(aparent) = &a.parent { + if !FileInfo::order(parent, aparent).is_eq() { + return std::cmp::Ordering::Greater; + } + } + } + + FileInfo::order(&a.file, &b.file) + } +}