trillium_include_dir/
globs.rs

1use crate::dir::Dir;
2use crate::file::File;
3use glob::{Pattern, PatternError};
4use std::path::Path;
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct Globs<'a> {
8    stack: Vec<DirEntry<'a>>,
9    pattern: Pattern,
10}
11
12impl<'a> Dir<'a> {
13    /// Search for a file or directory with a glob pattern.
14    pub fn find(&self, glob: &str) -> Result<impl Iterator<Item = DirEntry<'a>>, PatternError> {
15        let pattern = Pattern::new(glob)?;
16
17        Ok(Globs::new(pattern, *self))
18    }
19
20    pub(crate) fn dir_entries(&self) -> impl Iterator<Item = DirEntry<'a>> {
21        let files = self.files().iter().map(|f| DirEntry::File(*f));
22        let dirs = self.dirs().iter().map(|d| DirEntry::Dir(*d));
23
24        files.chain(dirs)
25    }
26}
27
28impl<'a> Globs<'a> {
29    pub(crate) fn new(pattern: Pattern, root: Dir<'a>) -> Globs<'a> {
30        let stack = vec![DirEntry::Dir(root)];
31        Globs { stack, pattern }
32    }
33
34    fn fill_buffer(&mut self, item: &DirEntry<'a>) {
35        if let DirEntry::Dir(ref dir) = *item {
36            self.stack.extend(dir.dir_entries());
37        }
38    }
39}
40
41impl<'a> Iterator for Globs<'a> {
42    type Item = DirEntry<'a>;
43
44    fn next(&mut self) -> Option<Self::Item> {
45        while let Some(item) = self.stack.pop() {
46            self.fill_buffer(&item);
47
48            if self.pattern.matches_path(item.path()) {
49                return Some(item);
50            }
51        }
52
53        None
54    }
55}
56
57/// Entries returned by the Globs iterator
58#[derive(Debug, Copy, Clone, PartialEq)]
59pub enum DirEntry<'a> {
60    /// A file with its contents stored in a &'static [u8].
61    File(File<'a>),
62    /// A directory entry.
63    Dir(Dir<'a>),
64}
65
66impl<'a> DirEntry<'a> {
67    /// Get the entries's path
68    pub fn path(&self) -> &'a Path {
69        match *self {
70            DirEntry::File(f) => f.path(),
71            DirEntry::Dir(d) => d.path(),
72        }
73    }
74}