2019-10-29 00:00:00 +00:00
|
|
|
// build-pass
|
2018-01-02 13:11:41 +00:00
|
|
|
|
2015-01-16 22:19:41 +00:00
|
|
|
// Regression test for #20797.
|
|
|
|
|
|
|
|
use std::default::Default;
|
2015-03-17 20:33:26 +00:00
|
|
|
use std::io;
|
|
|
|
use std::fs;
|
2015-03-23 22:54:39 +00:00
|
|
|
use std::path::PathBuf;
|
2015-03-17 20:33:26 +00:00
|
|
|
|
|
|
|
pub trait PathExtensions {
|
|
|
|
fn is_dir(&self) -> bool { false }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PathExtensions for PathBuf {}
|
2015-01-16 22:19:41 +00:00
|
|
|
|
|
|
|
/// A strategy for acquiring more subpaths to walk.
|
|
|
|
pub trait Strategy {
|
2015-03-17 20:33:26 +00:00
|
|
|
type P: PathExtensions;
|
2019-02-09 21:23:30 +00:00
|
|
|
/// Gets additional subpaths from a given path.
|
2015-03-17 20:33:26 +00:00
|
|
|
fn get_more(&self, item: &Self::P) -> io::Result<Vec<Self::P>>;
|
|
|
|
/// Determine whether a path should be walked further.
|
|
|
|
/// This is run against each item from `get_more()`.
|
|
|
|
fn prune(&self, p: &Self::P) -> bool;
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The basic fully-recursive strategy. Nothing is pruned.
|
2015-03-30 13:38:27 +00:00
|
|
|
#[derive(Copy, Clone, Default)]
|
2015-01-16 22:19:41 +00:00
|
|
|
pub struct Recursive;
|
|
|
|
|
|
|
|
impl Strategy for Recursive {
|
2015-03-17 20:33:26 +00:00
|
|
|
type P = PathBuf;
|
|
|
|
fn get_more(&self, p: &PathBuf) -> io::Result<Vec<PathBuf>> {
|
|
|
|
Ok(fs::read_dir(p).unwrap().map(|s| s.unwrap().path()).collect())
|
|
|
|
}
|
2015-01-16 22:19:41 +00:00
|
|
|
|
2015-03-17 20:33:26 +00:00
|
|
|
fn prune(&self, _: &PathBuf) -> bool { false }
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A directory walker of `P` using strategy `S`.
|
|
|
|
pub struct Subpaths<S: Strategy> {
|
|
|
|
stack: Vec<S::P>,
|
|
|
|
strategy: S,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Strategy> Subpaths<S> {
|
2019-02-09 21:23:30 +00:00
|
|
|
/// Creates a directory walker with a root path and strategy.
|
2015-03-17 20:33:26 +00:00
|
|
|
pub fn new(p: &S::P, strategy: S) -> io::Result<Subpaths<S>> {
|
2016-03-23 03:01:37 +00:00
|
|
|
let stack = strategy.get_more(p)?;
|
2015-03-17 20:33:26 +00:00
|
|
|
Ok(Subpaths { stack: stack, strategy: strategy })
|
|
|
|
}
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Default + Strategy> Subpaths<S> {
|
2019-02-09 21:23:30 +00:00
|
|
|
/// Creates a directory walker with a root path and a default strategy.
|
2015-03-17 20:33:26 +00:00
|
|
|
pub fn walk(p: &S::P) -> io::Result<Subpaths<S>> {
|
|
|
|
Subpaths::new(p, Default::default())
|
|
|
|
}
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Default + Strategy> Default for Subpaths<S> {
|
2015-03-17 20:33:26 +00:00
|
|
|
fn default() -> Subpaths<S> {
|
|
|
|
Subpaths { stack: Vec::new(), strategy: Default::default() }
|
|
|
|
}
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Strategy> Iterator for Subpaths<S> {
|
2015-03-17 20:33:26 +00:00
|
|
|
type Item = S::P;
|
|
|
|
fn next (&mut self) -> Option<S::P> {
|
|
|
|
let mut opt_path = self.stack.pop();
|
|
|
|
while opt_path.is_some() && self.strategy.prune(opt_path.as_ref().unwrap()) {
|
|
|
|
opt_path = self.stack.pop();
|
|
|
|
}
|
|
|
|
match opt_path {
|
|
|
|
Some(path) => {
|
|
|
|
if path.is_dir() {
|
|
|
|
let result = self.strategy.get_more(&path);
|
|
|
|
match result {
|
2015-06-10 16:22:20 +00:00
|
|
|
Ok(dirs) => { self.stack.extend(dirs); },
|
2015-03-17 20:33:26 +00:00
|
|
|
Err(..) => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(path)
|
|
|
|
}
|
|
|
|
None => None,
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-23 22:54:39 +00:00
|
|
|
fn _foo() {
|
|
|
|
let _walker: Subpaths<Recursive> = Subpaths::walk(&PathBuf::from("/home")).unwrap();
|
2015-01-16 22:19:41 +00:00
|
|
|
}
|
2015-03-17 20:33:26 +00:00
|
|
|
|
|
|
|
fn main() {}
|