Skip to main content

weavatrix_scan/
walk_iter.rs

1use crate::walk_types::{WalkEntry, WalkError, WalkOperation};
2use crate::walker::Walker;
3
4impl Iterator for Walker {
5    type Item = Result<WalkEntry, WalkError>;
6
7    fn next(&mut self) -> Option<Self::Item> {
8        'walk: loop {
9            if self.finished {
10                return None;
11            }
12            if self.yield_root {
13                self.yield_root = false;
14                let root = self.root.as_ref().clone();
15                let entry = self.visit(
16                    root,
17                    0,
18                    Some(self.root_file_type.expect("root metadata is present")),
19                    None,
20                );
21                match entry {
22                    Ok(entry) if entry.depth() >= self.options.min_depth => {
23                        return Some(Ok(entry));
24                    }
25                    Ok(_) => continue,
26                    Err(error) => return Some(self.yield_error(error)),
27                }
28            }
29            if let Some(error) = self.schedule_pending_directory() {
30                return Some(self.yield_error(error));
31            }
32            loop {
33                let frame = self.frames.last_mut()?;
34                let depth = frame.depth + 1;
35                let entry = match frame.entries.next() {
36                    Some(Ok(entry)) => entry,
37                    Some(Err(source)) => {
38                        let error =
39                            WalkError::new(&frame.path, depth, WalkOperation::ReadEntry, source);
40                        return Some(self.yield_error(error));
41                    }
42                    None => {
43                        let was_open = frame.entries.is_open();
44                        let identity = frame.identity;
45                        self.frames.pop();
46                        if was_open {
47                            self.open_handles -= 1;
48                        }
49                        if let Some(identity) = identity {
50                            self.active_directories.remove(&identity);
51                        }
52                        continue;
53                    }
54                };
55                let path = entry.path();
56                let file_type = match entry.file_type() {
57                    Ok(file_type) => file_type,
58                    Err(source) => {
59                        let error =
60                            WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
61                        return Some(self.yield_error(error));
62                    }
63                };
64                let bytes = if self.options.collect_metadata && file_type.is_file() {
65                    match entry.metadata() {
66                        Ok(metadata) => Some(metadata.len()),
67                        Err(source) => {
68                            let error =
69                                WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
70                            return Some(self.yield_error(error));
71                        }
72                    }
73                } else {
74                    None
75                };
76                match self.visit(path, depth, Some(file_type), bytes) {
77                    Ok(entry) if entry.depth() >= self.options.min_depth => {
78                        return Some(Ok(entry));
79                    }
80                    Ok(_) => continue 'walk,
81                    Err(error) => return Some(self.yield_error(error)),
82                }
83            }
84        }
85    }
86}