git_ref/store/file/loose/
iter.rs1use std::path::{Path, PathBuf};
2
3use git_features::fs::walkdir::DirEntryIter;
4use git_object::bstr::ByteSlice;
5
6use crate::{file::iter::LooseThenPacked, store_impl::file, BString, FullName};
7
8pub(in crate::store_impl::file) struct SortedLoosePaths {
10 pub(crate) base: PathBuf,
11 filename_prefix: Option<BString>,
12 file_walk: Option<DirEntryIter>,
13}
14
15impl SortedLoosePaths {
16 pub fn at(path: impl AsRef<Path>, base: impl Into<PathBuf>, filename_prefix: Option<BString>) -> Self {
17 let path = path.as_ref();
18 SortedLoosePaths {
19 base: base.into(),
20 filename_prefix,
21 file_walk: path.is_dir().then(|| {
22 git_features::fs::walkdir_sorted_new(path, git_features::fs::walkdir::Parallelism::Serial).into_iter()
24 }),
25 }
26 }
27}
28
29impl Iterator for SortedLoosePaths {
30 type Item = std::io::Result<(PathBuf, FullName)>;
31
32 fn next(&mut self) -> Option<Self::Item> {
33 for entry in self.file_walk.as_mut()?.by_ref() {
34 match entry {
35 Ok(entry) => {
36 if !entry.file_type().is_file() {
37 continue;
38 }
39 let full_path = entry.path().to_owned();
40 if let Some((prefix, name)) = self
41 .filename_prefix
42 .as_deref()
43 .and_then(|prefix| full_path.file_name().map(|name| (prefix, name)))
44 {
45 match git_path::os_str_into_bstr(name) {
46 Ok(name) => {
47 if !name.starts_with(prefix) {
48 continue;
49 }
50 }
51 Err(_) => continue, }
53 }
54 let full_name = full_path
55 .strip_prefix(&self.base)
56 .expect("prefix-stripping cannot fail as prefix is our root");
57 let full_name = match git_path::try_into_bstr(full_name) {
58 Ok(name) => {
59 let name = git_path::to_unix_separators_on_windows(name);
60 name.into_owned()
61 }
62 Err(_) => continue, };
64
65 if git_validate::reference::name_partial(full_name.as_bstr()).is_ok() {
66 let name = FullName(full_name);
67 return Some(Ok((full_path, name)));
68 } else {
69 continue;
70 }
71 }
72 Err(err) => return Some(Err(err.into_io_error().expect("no symlink related errors"))),
73 }
74 }
75 None
76 }
77}
78
79impl file::Store {
80 pub fn loose_iter(&self) -> std::io::Result<LooseThenPacked<'_, '_>> {
86 self.iter_packed(None)
87 }
88
89 pub fn loose_iter_prefixed(&self, prefix: impl AsRef<Path>) -> std::io::Result<LooseThenPacked<'_, '_>> {
93 self.iter_prefixed_packed(prefix, None)
94 }
95}