read_dir_all/
lib.rs

1//! simple, recursive readdir
2
3#![forbid(unsafe_code, rust_2018_idioms)]
4#![deny(missing_debug_implementations, nonstandard_style)]
5#![warn(missing_docs, future_incompatible, unreachable_pub)]
6
7use std::fs::{self, DirEntry, ReadDir};
8use std::io;
9use std::path::Path;
10
11/// Recursively iterate over all entries in a directory.
12pub fn read_dir_all<P: AsRef<Path>>(path: P) -> io::Result<ReadDirAll> {
13    let reader = fs::read_dir(path)?;
14    Ok(ReadDirAll {
15        readers: vec![reader],
16    })
17}
18
19/// Recursively iterates over all entries in a directory.
20///
21/// This operation recurses over all entries in a directory in a depth-first
22/// way, following symlinks along the way.
23#[derive(Debug)]
24pub struct ReadDirAll {
25    readers: Vec<ReadDir>,
26}
27
28impl ReadDirAll {
29    /// Visit a directory, and step into it following symlinks along the way.
30    fn visit_dir(&mut self, entry: DirEntry) -> Result<DirEntry, io::Error> {
31        // Step into the directory on the next iteration.
32        let reader = fs::read_dir(entry.path())?;
33        self.readers.push(reader);
34
35        // Allows the current directory to be yielded from the iterator.
36        Ok(entry)
37    }
38}
39
40impl Iterator for ReadDirAll {
41    type Item = io::Result<DirEntry>;
42
43    fn next(&mut self) -> Option<Self::Item> {
44        loop {
45            // Try and get the last reader on the stack.
46            // Once we have no more readers left, we're done.
47            let reader = self.readers.last_mut()?;
48
49            match reader.next() {
50                // If the current reader is done, continue with the parent.
51                None => self.readers.pop(),
52
53                // If the entry is a directory, step into it.
54                Some(Ok(entry)) if entry.path().is_dir() => return Some(self.visit_dir(entry)),
55
56                // Otherwise, yield whatever output the reader provided.
57                result => return result,
58            };
59        }
60    }
61}