about summary refs log tree commit diff
path: root/tests/ui/issues/issue-20797.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/issues/issue-20797.rs')
-rw-r--r--tests/ui/issues/issue-20797.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/tests/ui/issues/issue-20797.rs b/tests/ui/issues/issue-20797.rs
new file mode 100644
index 00000000000..ef0e72571ef
--- /dev/null
+++ b/tests/ui/issues/issue-20797.rs
@@ -0,0 +1,93 @@
+// build-pass
+
+// Regression test for #20797.
+
+use std::default::Default;
+use std::io;
+use std::fs;
+use std::path::PathBuf;
+
+pub trait PathExtensions {
+    fn is_dir(&self) -> bool { false }
+}
+
+impl PathExtensions for PathBuf {}
+
+/// A strategy for acquiring more subpaths to walk.
+pub trait Strategy {
+    type P: PathExtensions;
+    /// Gets additional subpaths from a given path.
+    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;
+}
+
+/// The basic fully-recursive strategy. Nothing is pruned.
+#[derive(Copy, Clone, Default)]
+pub struct Recursive;
+
+impl Strategy for Recursive {
+    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())
+    }
+
+    fn prune(&self, _: &PathBuf) -> bool { false }
+}
+
+/// A directory walker of `P` using strategy `S`.
+pub struct Subpaths<S: Strategy> {
+    stack: Vec<S::P>,
+    strategy: S,
+}
+
+impl<S: Strategy> Subpaths<S> {
+    /// Creates a directory walker with a root path and strategy.
+    pub fn new(p: &S::P, strategy: S) -> io::Result<Subpaths<S>> {
+        let stack = strategy.get_more(p)?;
+        Ok(Subpaths { stack: stack, strategy: strategy })
+    }
+}
+
+impl<S: Default + Strategy> Subpaths<S> {
+    /// Creates a directory walker with a root path and a default strategy.
+    pub fn walk(p: &S::P) -> io::Result<Subpaths<S>> {
+        Subpaths::new(p, Default::default())
+    }
+}
+
+impl<S: Default + Strategy> Default for Subpaths<S> {
+    fn default() -> Subpaths<S> {
+        Subpaths { stack: Vec::new(), strategy: Default::default() }
+    }
+}
+
+impl<S: Strategy> Iterator for Subpaths<S> {
+    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 {
+                        Ok(dirs) => { self.stack.extend(dirs); },
+                        Err(..) => { }
+                    }
+                }
+                Some(path)
+            }
+            None => None,
+        }
+    }
+}
+
+fn _foo() {
+    let _walker: Subpaths<Recursive> = Subpaths::walk(&PathBuf::from("/home")).unwrap();
+}
+
+fn main() {}