From 72af75c035e6ae459914654c654243b435ace255 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 1 Oct 2018 17:24:50 +0300 Subject: Change: split out fswaslking to its own module --- src/fswalk.rs | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/fswalk.rs diff --git a/src/fswalk.rs b/src/fswalk.rs new file mode 100644 index 0000000..ac95540 --- /dev/null +++ b/src/fswalk.rs @@ -0,0 +1,117 @@ +use std::io; +use std::path::PathBuf; +use std::cmp::Ordering; + +// A filesystem entry: directory, file, symlink, etc +#[derive(Debug)] +pub struct Entry { + path: PathBuf, +} + +impl Entry { + fn new(path: &PathBuf) -> Entry { + Entry { + path: path.clone(), + } + } + + pub fn path(&self) -> String { + self.path.to_string_lossy().to_string() + } +} + +impl Eq for Entry {} + +impl PartialEq for Entry { + fn eq(&self, other: &Entry) -> bool { + self.path == other.path + } +} + +impl Ord for Entry { + fn cmp(&self, other: &Entry) -> Ordering { + self.path.cmp(&other.path) + } +} + +impl PartialOrd for Entry { + fn partial_cmp(&self, other: &Entry) -> Option { + Some(self.path.cmp(&other.path)) + } +} + +// Keep two stacks of Entry values, sorted in ascending order. The +// first stack has non-directories. When we iterate, we return a +// directory, then of its non-dirs, then recurse each of its subdirs. +#[derive(Debug)] +pub struct DirTree { + entries: Vec, + dirs: Vec, +} + +impl DirTree { + pub fn new(path: &str) -> DirTree { + let mut dt = DirTree::empty(); + dt.add_dir(&PathBuf::from(path)); + dt + } + + fn empty() -> DirTree { + DirTree { + entries: Vec::new(), + dirs: Vec::new(), + } + } + + fn add_dir(&mut self, path: &PathBuf) { + let entry = Entry::new(path); + self.dirs.push(entry); + } + + fn add_entries(&mut self, path: &PathBuf) -> io::Result<()> { + let mut entries = Vec::new(); + let mut dirs = Vec::new(); + for dir_entry in path.read_dir()? { + let dir_entry = dir_entry?; + let metadata = dir_entry.metadata()?; + let entry = Entry::new(&dir_entry.path()); + if metadata.is_dir() { + dirs.push(entry); + } else { + entries.push(entry); + } + } + + entries.sort(); + entries.reverse(); + for e in entries { + self.entries.push(e); + } + + dirs.sort(); + dirs.reverse(); + for e in dirs { + self.dirs.push(e); + } + + Ok(()) + } +} + +impl Iterator for DirTree { + type Item = Entry; + + fn next(&mut self) -> Option { + if let Some(e) = self.entries.pop() { + Some(e) + } else if let Some(e) = self.dirs.pop() { + if let Ok(_) = self.add_entries(&e.path) { + // We ignore any errors from adding entries. Boo. Not + // sure how I'd propagate errors, from a next method. + } + Some(e) + } else { + None + } + } +} -- cgit v1.2.1