1#![allow(dead_code)]
4
5mod filter;
6#[cfg(test)]
7mod test;
8
9use std::*;
10
11type Result<T> = io::Result<T>;
13
14#[derive(Default)]
15pub struct DirIterator {
17 stack: Vec<fs::ReadDir>,
19 config: DirIteratorConfig,
21}
22
23impl DirIterator {
24 pub fn current() -> DirIteratorBuilder {
26 Self::try_current().expect("invalid current directory")
27 }
28
29 pub fn try_current() -> Result<DirIteratorBuilder> {
31 Self::from_path(env::current_dir()?)
32 }
33
34 pub fn build_current() -> impl Iterator<Item = fs::DirEntry> {
36 Self::current().build()
37 }
38
39 pub fn try_build_current() -> Result<impl Iterator<Item = fs::DirEntry>> {
41 Ok(Self::try_current()?.build())
42 }
43
44 pub fn from_path(path: impl AsRef<path::Path>) -> Result<DirIteratorBuilder> {
46 Ok(DirIteratorBuilder(Self {
47 stack: vec![fs::read_dir(path)?],
48 ..Default::default()
49 }))
50 }
51
52 pub fn build_from_path(
54 path: impl AsRef<path::Path>,
55 ) -> Result<impl Iterator<Item = fs::DirEntry>> {
56 Ok(Self::from_path(path)?.build())
57 }
58
59 fn from_builder(builder: DirIteratorBuilder) -> Self {
61 builder.0
62 }
63}
64
65impl Iterator for DirIterator {
66 type Item = Result<fs::DirEntry>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 loop {
70 if let Some(it) = self.stack.last_mut() {
72 match it.next() {
74 Some(Ok(item)) => {
76 match item.file_type() {
78 Ok(file_type) => {
79 if self.config.ignore.iter().any(|ignore| {
81 ignore.is_match(item.file_name().as_encoded_bytes())
82 }) {
83 continue;
84 }
85 if file_type.is_dir() {
87 match fs::read_dir(item.path()) {
88 Ok(dir_entry) => self.stack.push(dir_entry),
89 Err(err) => return Some(Err(err)),
90 }
91 }
92 return Some(Ok(item));
94 }
95 Err(err) => return Some(Err(err)),
97 }
98 }
99 None => {
100 self.stack.pop()?;
102 }
103 err => return err,
104 }
105 } else {
106 return None;
107 }
108 }
109 }
110}
111
112#[derive(Default)]
114struct DirIteratorConfig {
115 ignore: Vec<wc::Wildcard<'static>>,
117}
118
119#[derive(Default)]
121pub struct DirIteratorBuilder(DirIterator);
122
123impl DirIteratorBuilder {
124 pub fn build(self) -> impl Iterator<Item = fs::DirEntry> {
126 DirIterator::from_builder(self).flatten()
127 }
128
129 pub fn ignore(mut self, wildcard: &'static str) -> Self {
131 self.0
132 .config
133 .ignore
134 .push(wc::Wildcard::new(wildcard.as_bytes()).expect("misformed wildcard"));
135 self
136 }
137}