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
use crate::loose::Db;
use git_object::owned;
use quick_error::quick_error;
use walkdir::WalkDir;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        WalkDir(err: walkdir::Error) {
            source(err)
        }
    }
}

/// Iteration and traversal
impl Db {
    pub fn iter(&self) -> impl Iterator<Item = Result<owned::Id, Error>> {
        use std::path::Component::Normal;
        // TODO: Put this behind a feature flag in git-features and allow iterting with jwalk
        WalkDir::new(&self.path)
            .min_depth(2)
            .max_depth(3)
            .follow_links(false)
            .into_iter()
            .filter_map(|res| {
                let mut is_valid_path = false;
                let e = res.map_err(Error::WalkDir).map(|e| {
                    let p = e.path();
                    let (c1, c2) = p.components().fold((None, None), |(_c1, c2), cn| (c2, Some(cn)));
                    if let (Some(Normal(c1)), Some(Normal(c2))) = (c1, c2) {
                        if c1.len() == 2 && c2.len() == 38 {
                            if let (Some(c1), Some(c2)) = (c1.to_str(), c2.to_str()) {
                                let mut buf = [0u8; 40];
                                {
                                    let (first_byte, rest) = buf.split_at_mut(2);
                                    first_byte.copy_from_slice(c1.as_bytes());
                                    rest.copy_from_slice(c2.as_bytes());
                                }
                                if let Ok(b) = owned::Id::from_40_bytes_in_hex(&buf[..]) {
                                    is_valid_path = true;
                                    return b;
                                }
                            }
                        }
                    }
                    owned::Id::null_sha1()
                });
                if is_valid_path {
                    Some(e)
                } else {
                    None
                }
            })
    }
}