1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use std::cell::{RefCell,RefMut};
use std::path::PathBuf;
use std::result;

pub mod fs_tree_builder;
pub mod into_iter;
pub mod iter;

use crate::error::Error;
use crate::read_dir::ReadDir;
use self::into_iter::IntoIter;
use self::iter::Iter;

pub type Result = result::Result<PathBuf, Error>;

///
/// An iterator that traverses a file system directory tree.
///
#[derive(Default)]
pub struct FsTree
{
    top: PathBuf,
    stack: RefCell<Vec<ReadDir>>,
    ignore_files: Option<Vec<PathBuf>>,
    ignore_paths: Option<Vec<PathBuf>>,
    max_depth: Option<usize>,
    min_depth: usize
}

impl FsTree {
    pub fn iter(&self) -> Iter {
        Iter(self)
    }

    pub(crate) fn top(&self) -> &PathBuf {
        &self.top
    }

    pub(crate) fn stack(&self) -> RefMut<Vec<ReadDir>> {
        self.stack.borrow_mut()
    }

    pub(crate) fn push_dir(&self, path: &PathBuf) -> result::Result<(), Error> {
        if let Some(max_depth) = self.max_depth() {
            if self.depth() >= max_depth {
                return Ok(());
            }
        }

        let read_dir = ReadDir::new(path)?;
        self.stack().push(read_dir);

        Ok(())
    }

    pub(crate) fn depth(&self) -> usize {
        self.stack().len()
    }

    pub(crate) fn ignore_file(&self, path: &PathBuf) -> bool {
        if let Some(ignore_files) = &self.ignore_files {
            ignore_files.contains(path)
        } else {
            false
        }
    }

    pub(crate) fn ignore_path(&self, path: &PathBuf) -> bool {
        if let Some(ignore_paths) = &self.ignore_paths {
            ignore_paths.contains(path)
        } else {
            false
        }
    }

    pub(crate) fn max_depth(&self) -> Option<usize> {
        self.max_depth
    }

    pub(crate) fn min_depth(&self) -> usize {
        self.min_depth
    }
}

impl IntoIterator for FsTree {
    type Item = Result;
    type IntoIter = IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter(self)
    }
}

impl<'a> IntoIterator for &'a FsTree {
    type Item = Result;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Iter(self)
    }
}