]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
85aaf69f SL |
11 | // Regression test for #20797. |
12 | ||
c34b1796 AL |
13 | // pretty-expanded FIXME #23616 |
14 | ||
54a0048b SL |
15 | #![feature(question_mark)] |
16 | ||
85aaf69f | 17 | use std::default::Default; |
c34b1796 AL |
18 | use std::io; |
19 | use std::fs; | |
20 | use std::path::PathBuf; | |
21 | ||
22 | pub trait PathExtensions { | |
23 | fn is_dir(&self) -> bool { false } | |
24 | } | |
25 | ||
26 | impl PathExtensions for PathBuf {} | |
85aaf69f SL |
27 | |
28 | /// A strategy for acquiring more subpaths to walk. | |
29 | pub trait Strategy { | |
c34b1796 AL |
30 | type P: PathExtensions; |
31 | /// Get additional subpaths from a given path. | |
32 | fn get_more(&self, item: &Self::P) -> io::Result<Vec<Self::P>>; | |
33 | /// Determine whether a path should be walked further. | |
34 | /// This is run against each item from `get_more()`. | |
35 | fn prune(&self, p: &Self::P) -> bool; | |
85aaf69f SL |
36 | } |
37 | ||
38 | /// The basic fully-recursive strategy. Nothing is pruned. | |
c34b1796 | 39 | #[derive(Copy, Clone, Default)] |
85aaf69f SL |
40 | pub struct Recursive; |
41 | ||
42 | impl Strategy for Recursive { | |
c34b1796 AL |
43 | type P = PathBuf; |
44 | fn get_more(&self, p: &PathBuf) -> io::Result<Vec<PathBuf>> { | |
45 | Ok(fs::read_dir(p).unwrap().map(|s| s.unwrap().path()).collect()) | |
46 | } | |
85aaf69f | 47 | |
c34b1796 | 48 | fn prune(&self, _: &PathBuf) -> bool { false } |
85aaf69f SL |
49 | } |
50 | ||
51 | /// A directory walker of `P` using strategy `S`. | |
52 | pub struct Subpaths<S: Strategy> { | |
53 | stack: Vec<S::P>, | |
54 | strategy: S, | |
55 | } | |
56 | ||
57 | impl<S: Strategy> Subpaths<S> { | |
c34b1796 AL |
58 | /// Create a directory walker with a root path and strategy. |
59 | pub fn new(p: &S::P, strategy: S) -> io::Result<Subpaths<S>> { | |
54a0048b | 60 | let stack = strategy.get_more(p)?; |
c34b1796 AL |
61 | Ok(Subpaths { stack: stack, strategy: strategy }) |
62 | } | |
85aaf69f SL |
63 | } |
64 | ||
65 | impl<S: Default + Strategy> Subpaths<S> { | |
c34b1796 AL |
66 | /// Create a directory walker with a root path and a default strategy. |
67 | pub fn walk(p: &S::P) -> io::Result<Subpaths<S>> { | |
68 | Subpaths::new(p, Default::default()) | |
69 | } | |
85aaf69f SL |
70 | } |
71 | ||
72 | impl<S: Default + Strategy> Default for Subpaths<S> { | |
c34b1796 AL |
73 | fn default() -> Subpaths<S> { |
74 | Subpaths { stack: Vec::new(), strategy: Default::default() } | |
75 | } | |
85aaf69f SL |
76 | } |
77 | ||
78 | impl<S: Strategy> Iterator for Subpaths<S> { | |
c34b1796 AL |
79 | type Item = S::P; |
80 | fn next (&mut self) -> Option<S::P> { | |
81 | let mut opt_path = self.stack.pop(); | |
82 | while opt_path.is_some() && self.strategy.prune(opt_path.as_ref().unwrap()) { | |
83 | opt_path = self.stack.pop(); | |
84 | } | |
85 | match opt_path { | |
86 | Some(path) => { | |
87 | if path.is_dir() { | |
88 | let result = self.strategy.get_more(&path); | |
89 | match result { | |
62682a34 | 90 | Ok(dirs) => { self.stack.extend(dirs); }, |
c34b1796 AL |
91 | Err(..) => { } |
92 | } | |
93 | } | |
94 | Some(path) | |
95 | } | |
96 | None => None, | |
85aaf69f | 97 | } |
85aaf69f | 98 | } |
85aaf69f SL |
99 | } |
100 | ||
c34b1796 AL |
101 | fn _foo() { |
102 | let _walker: Subpaths<Recursive> = Subpaths::walk(&PathBuf::from("/home")).unwrap(); | |
85aaf69f | 103 | } |
c34b1796 AL |
104 | |
105 | fn main() {} |