1#[cfg(feature = "walkdir")]
10mod shared {
11 pub enum Parallelism {
13 Serial,
15 ThreadPoolPerTraversal {
17 thread_name: &'static str,
19 },
20 }
21}
22
23#[cfg(any(feature = "walkdir", feature = "fs-read-dir"))]
24mod walkdir_precompose {
25 use std::borrow::Cow;
26 use std::ffi::OsStr;
27 use std::path::Path;
28
29 #[derive(Debug)]
30 pub struct DirEntry<T: std::fmt::Debug> {
31 inner: T,
32 precompose_unicode: bool,
33 }
34
35 impl<T: std::fmt::Debug> DirEntry<T> {
36 pub fn new(inner: T, precompose_unicode: bool) -> Self {
38 Self {
39 inner,
40 precompose_unicode,
41 }
42 }
43 }
44
45 pub trait DirEntryApi {
46 fn path(&self) -> Cow<'_, Path>;
47 fn file_name(&self) -> Cow<'_, OsStr>;
48 fn file_type(&self) -> std::io::Result<std::fs::FileType>;
49 }
50
51 impl<T: DirEntryApi + std::fmt::Debug> DirEntry<T> {
52 pub fn path(&self) -> Cow<'_, Path> {
57 let path = self.inner.path();
58 if self.precompose_unicode {
59 gix_utils::str::precompose_path(path)
60 } else {
61 path
62 }
63 }
64
65 pub fn file_name(&self) -> Cow<'_, OsStr> {
67 let name = self.inner.file_name();
68 if self.precompose_unicode {
69 gix_utils::str::precompose_os_string(name)
70 } else {
71 name
72 }
73 }
74
75 pub fn file_type(&self) -> std::io::Result<std::fs::FileType> {
79 self.inner.file_type()
80 }
81 }
82
83 #[cfg(feature = "walkdir")]
86 pub struct WalkDir<T> {
87 pub(crate) inner: Option<T>,
88 pub(crate) precompose_unicode: bool,
89 }
90
91 #[cfg(feature = "walkdir")]
92 pub struct WalkDirIter<T, I, E>
93 where
94 T: Iterator<Item = Result<I, E>>,
95 I: DirEntryApi,
96 {
97 pub(crate) inner: T,
98 pub(crate) precompose_unicode: bool,
99 }
100
101 #[cfg(feature = "walkdir")]
102 impl<T, I, E> Iterator for WalkDirIter<T, I, E>
103 where
104 T: Iterator<Item = Result<I, E>>,
105 I: DirEntryApi + std::fmt::Debug,
106 {
107 type Item = Result<DirEntry<I>, E>;
108
109 fn next(&mut self) -> Option<Self::Item> {
110 self.inner
111 .next()
112 .map(|res| res.map(|entry| DirEntry::new(entry, self.precompose_unicode)))
113 }
114 }
115}
116
117#[cfg(feature = "fs-read-dir")]
119pub mod read_dir {
120 use std::borrow::Cow;
121 use std::ffi::OsStr;
122 use std::fs::FileType;
123 use std::path::Path;
124
125 pub type DirEntry = super::walkdir_precompose::DirEntry<std::fs::DirEntry>;
127
128 impl super::walkdir_precompose::DirEntryApi for std::fs::DirEntry {
129 fn path(&self) -> Cow<'_, Path> {
130 self.path().into()
131 }
132
133 fn file_name(&self) -> Cow<'_, OsStr> {
134 self.file_name().into()
135 }
136
137 fn file_type(&self) -> std::io::Result<FileType> {
138 self.file_type()
139 }
140 }
141}
142
143#[cfg(feature = "walkdir")]
145pub mod walkdir {
146 use std::borrow::Cow;
147 use std::ffi::OsStr;
148 use std::fs::FileType;
149 use std::path::Path;
150
151 pub use walkdir::Error;
152 use walkdir::{DirEntry as DirEntryImpl, WalkDir as WalkDirImpl};
153
154 pub type DirEntry = super::walkdir_precompose::DirEntry<DirEntryImpl>;
156 pub type WalkDir = super::walkdir_precompose::WalkDir<WalkDirImpl>;
158
159 pub use super::shared::Parallelism;
160
161 impl super::walkdir_precompose::DirEntryApi for DirEntryImpl {
162 fn path(&self) -> Cow<'_, Path> {
163 self.path().into()
164 }
165
166 fn file_name(&self) -> Cow<'_, OsStr> {
167 self.file_name().into()
168 }
169
170 fn file_type(&self) -> std::io::Result<FileType> {
171 Ok(self.file_type())
172 }
173 }
174
175 impl IntoIterator for WalkDir {
176 type Item = Result<DirEntry, walkdir::Error>;
177 type IntoIter = DirEntryIter;
178
179 fn into_iter(self) -> Self::IntoIter {
180 DirEntryIter {
181 inner: self.inner.expect("always set (builder fix)").into_iter(),
182 precompose_unicode: self.precompose_unicode,
183 }
184 }
185 }
186
187 impl WalkDir {
188 pub fn min_depth(mut self, min: usize) -> Self {
190 self.inner = Some(self.inner.take().expect("always set").min_depth(min));
191 self
192 }
193 pub fn max_depth(mut self, max: usize) -> Self {
195 self.inner = Some(self.inner.take().expect("always set").max_depth(max));
196 self
197 }
198 pub fn follow_links(mut self, toggle: bool) -> Self {
200 self.inner = Some(self.inner.take().expect("always set").follow_links(toggle));
201 self
202 }
203 }
204
205 pub fn walkdir_new(root: &Path, _: Parallelism, precompose_unicode: bool) -> WalkDir {
209 WalkDir {
210 inner: WalkDirImpl::new(root).into(),
211 precompose_unicode,
212 }
213 }
214
215 pub fn walkdir_sorted_new(root: &Path, _: Parallelism, precompose_unicode: bool) -> WalkDir {
219 WalkDir {
220 inner: WalkDirImpl::new(root)
221 .sort_by(|a, b| {
222 let storage_a;
223 let storage_b;
224 let a_name = match gix_path::os_str_into_bstr(a.file_name()) {
225 Ok(f) => f,
226 Err(_) => {
227 storage_a = a.file_name().to_string_lossy();
228 storage_a.as_ref().into()
229 }
230 };
231 let b_name = match gix_path::os_str_into_bstr(b.file_name()) {
232 Ok(f) => f,
233 Err(_) => {
234 storage_b = b.file_name().to_string_lossy();
235 storage_b.as_ref().into()
236 }
237 };
238 let common = a_name.len().min(b_name.len());
240 a_name[..common].cmp(&b_name[..common]).then_with(|| {
241 let a = a_name.get(common).or_else(|| a.file_type().is_dir().then_some(&b'/'));
242 let b = b_name.get(common).or_else(|| b.file_type().is_dir().then_some(&b'/'));
243 a.cmp(&b)
244 })
245 })
246 .into(),
247 precompose_unicode,
248 }
249 }
250
251 pub type DirEntryIter = super::walkdir_precompose::WalkDirIter<walkdir::IntoIter, DirEntryImpl, walkdir::Error>;
253}
254
255#[cfg(feature = "walkdir")]
256pub use self::walkdir::{walkdir_new, walkdir_sorted_new, WalkDir};
257
258pub fn open_options_no_follow() -> std::fs::OpenOptions {
262 #[cfg_attr(not(unix), allow(unused_mut))]
263 let mut options = std::fs::OpenOptions::new();
264 #[cfg(unix)]
265 {
266 use std::os::unix::fs::OpenOptionsExt;
270 options.custom_flags(libc::O_NOFOLLOW);
271 }
272 options
273}