diff options
author | Lars Wirzenius <liw@liw.fi> | 2018-10-01 17:24:50 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-10-01 17:24:50 +0300 |
commit | 72af75c035e6ae459914654c654243b435ace255 (patch) | |
tree | e7c6193fd63981a4e68022440c24c2fe0a66fdbb | |
parent | 21ec762dd8680a924cec7fec7197fffb3fa92fa7 (diff) | |
download | summainrs-72af75c035e6ae459914654c654243b435ace255.tar.gz |
Change: split out fswaslking to its own module
-rw-r--r-- | src/fswalk.rs | 117 |
1 files changed, 117 insertions, 0 deletions
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<Ordering> { + 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<Entry>, + dirs: Vec<Entry>, +} + +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<Entry> { + 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 + } + } +} |