1#![expect(missing_docs)]
16
17use std::borrow::Borrow;
18use std::fmt::Debug;
19use std::fmt::Error;
20use std::fmt::Formatter;
21use std::hash::Hash;
22use std::hash::Hasher;
23use std::sync::Arc;
24
25use itertools::Itertools as _;
26use pollster::FutureExt as _;
27
28use crate::backend;
29use crate::backend::BackendResult;
30use crate::backend::MergedTreeVal;
31use crate::backend::MergedTreeValueExt as _;
32use crate::backend::TreeEntriesNonRecursiveIterator;
33use crate::backend::TreeId;
34use crate::backend::TreeValue;
35use crate::backend::borrow_tree_value;
36use crate::matchers::Matcher;
37use crate::merge::Merge;
38use crate::repo_path::RepoPath;
39use crate::repo_path::RepoPathBuf;
40use crate::repo_path::RepoPathComponent;
41use crate::store::Store;
42
43#[derive(Clone)]
44pub struct Tree {
45 store: Arc<Store>,
46 dir: RepoPathBuf,
47 id: TreeId,
48 data: Arc<backend::Tree>,
49}
50
51impl Debug for Tree {
52 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
53 f.debug_struct("Tree")
54 .field("dir", &self.dir)
55 .field("id", &self.id)
56 .finish()
57 }
58}
59
60impl PartialEq for Tree {
61 fn eq(&self, other: &Self) -> bool {
62 self.id == other.id && self.dir == other.dir
63 }
64}
65
66impl Eq for Tree {}
67
68impl Hash for Tree {
69 fn hash<H: Hasher>(&self, state: &mut H) {
70 self.dir.hash(state);
71 self.id.hash(state);
72 }
73}
74
75impl Tree {
76 pub fn new(store: Arc<Store>, dir: RepoPathBuf, id: TreeId, data: Arc<backend::Tree>) -> Self {
77 Self {
78 store,
79 dir,
80 id,
81 data,
82 }
83 }
84
85 pub fn empty(store: Arc<Store>, dir: RepoPathBuf) -> Self {
86 let id = store.empty_tree_id().clone();
87 Self {
88 store,
89 dir,
90 id,
91 data: Arc::new(backend::Tree::default()),
92 }
93 }
94
95 pub fn store(&self) -> &Arc<Store> {
96 &self.store
97 }
98
99 pub fn dir(&self) -> &RepoPath {
100 &self.dir
101 }
102
103 pub fn id(&self) -> &TreeId {
104 &self.id
105 }
106
107 pub fn data(&self) -> &backend::Tree {
108 &self.data
109 }
110
111 pub fn entries_non_recursive(&self) -> TreeEntriesNonRecursiveIterator<'_> {
112 self.data.entries()
113 }
114
115 pub fn entries_matching<'matcher>(
116 &self,
117 matcher: &'matcher dyn Matcher,
118 ) -> TreeEntriesIterator<'matcher> {
119 TreeEntriesIterator::new(self.clone(), matcher)
120 }
121
122 pub fn value(&self, basename: &RepoPathComponent) -> Option<&TreeValue> {
123 self.data.value(basename)
124 }
125
126 pub async fn path_value(&self, path: &RepoPath) -> BackendResult<Option<TreeValue>> {
127 assert_eq!(self.dir(), RepoPath::root());
128 match path.split() {
129 Some((dir, basename)) => {
130 let tree = self.sub_tree_recursive(dir).await?;
131 Ok(tree.and_then(|tree| tree.data.value(basename).cloned()))
132 }
133 None => Ok(Some(TreeValue::Tree(self.id.clone()))),
134 }
135 }
136
137 pub async fn sub_tree(&self, name: &RepoPathComponent) -> BackendResult<Option<Self>> {
138 if let Some(sub_tree) = self.data.value(name) {
139 match sub_tree {
140 TreeValue::Tree(sub_tree_id) => {
141 let subdir = self.dir.join(name);
142 let sub_tree = self.store.get_tree(subdir, sub_tree_id).await?;
143 Ok(Some(sub_tree))
144 }
145 _ => Ok(None),
146 }
147 } else {
148 Ok(None)
149 }
150 }
151
152 async fn known_sub_tree(&self, subdir: RepoPathBuf, id: &TreeId) -> Self {
153 self.store.get_tree(subdir, id).await.unwrap()
154 }
155
156 pub async fn sub_tree_recursive(&self, path: &RepoPath) -> BackendResult<Option<Self>> {
158 let mut current_tree = self.clone();
159 for name in path.components() {
160 match current_tree.sub_tree(name).await? {
161 None => {
162 return Ok(None);
163 }
164 Some(sub_tree) => {
165 current_tree = sub_tree;
166 }
167 }
168 }
169 Ok(Some(current_tree))
173 }
174}
175
176pub struct TreeEntriesIterator<'matcher> {
177 stack: Vec<TreeEntriesDirItem>,
178 matcher: &'matcher dyn Matcher,
179}
180
181struct TreeEntriesDirItem {
182 tree: Tree,
183 entries: Vec<(RepoPathBuf, TreeValue)>,
184}
185
186impl From<Tree> for TreeEntriesDirItem {
187 fn from(tree: Tree) -> Self {
188 let mut entries = tree
189 .entries_non_recursive()
190 .map(|entry| (tree.dir().join(entry.name()), entry.value().clone()))
191 .collect_vec();
192 entries.reverse();
193 Self { tree, entries }
194 }
195}
196
197impl<'matcher> TreeEntriesIterator<'matcher> {
198 fn new(tree: Tree, matcher: &'matcher dyn Matcher) -> Self {
199 Self {
201 stack: vec![TreeEntriesDirItem::from(tree)],
202 matcher,
203 }
204 }
205}
206
207impl Iterator for TreeEntriesIterator<'_> {
208 type Item = (RepoPathBuf, TreeValue);
209
210 fn next(&mut self) -> Option<Self::Item> {
211 while let Some(top) = self.stack.last_mut() {
212 if let Some((path, value)) = top.entries.pop() {
213 match value {
214 TreeValue::Tree(id) => {
215 if self.matcher.visit(&path).is_nothing() {
217 continue;
218 }
219 let subtree = top.tree.known_sub_tree(path, &id).block_on();
220 self.stack.push(TreeEntriesDirItem::from(subtree));
221 }
222 value => {
223 if self.matcher.matches(&path) {
224 return Some((path, value));
225 }
226 }
227 }
228 } else {
229 self.stack.pop();
230 }
231 }
232 None
233 }
234}
235
236#[expect(async_fn_in_trait)]
240pub trait ToTreeMergeExt {
241 async fn to_tree_merge(
246 &self,
247 store: &Arc<Store>,
248 dir: &RepoPath,
249 ) -> BackendResult<Option<Merge<Tree>>>;
250}
251
252impl<T> ToTreeMergeExt for Merge<Option<T>>
253where
254 T: Borrow<TreeValue>,
255{
256 async fn to_tree_merge(
257 &self,
258 store: &Arc<Store>,
259 dir: &RepoPath,
260 ) -> BackendResult<Option<Merge<Tree>>> {
261 let tree_id_merge = self.try_map(|term| match borrow_tree_value(term.as_ref()) {
262 None => Ok(None),
263 Some(TreeValue::Tree(id)) => Ok(Some(id)),
264 Some(_) => Err(()),
265 });
266 if let Ok(tree_id_merge) = tree_id_merge {
267 Ok(Some(
268 tree_id_merge
269 .try_map_async(async |id| {
270 if let Some(id) = id {
271 store.get_tree(dir.to_owned(), id).await
272 } else {
273 Ok(Tree::empty(store.clone(), dir.to_owned()))
274 }
275 })
276 .await?,
277 ))
278 } else {
279 Ok(None)
280 }
281 }
282}
283
284#[expect(async_fn_in_trait)]
288pub trait TreeMergeExt: Sized {
289 fn dir(&self) -> &RepoPath;
291
292 fn value(&self, basename: &RepoPathComponent) -> MergedTreeVal<'_>;
297
298 async fn sub_tree(&self, name: &RepoPathComponent) -> BackendResult<Option<Self>>;
302
303 async fn sub_tree_recursive(&self, path: &RepoPath) -> BackendResult<Option<Self>>;
305}
306
307impl TreeMergeExt for Merge<Tree> {
308 fn dir(&self) -> &RepoPath {
309 debug_assert!(self.iter().map(|tree| tree.dir()).all_equal());
310 self.first().dir()
311 }
312
313 fn value(&self, basename: &RepoPathComponent) -> MergedTreeVal<'_> {
314 if let Some(tree) = self.as_resolved() {
315 return Merge::resolved(tree.value(basename));
316 }
317 let same_change = self.first().store().merge_options().same_change;
318 let value = self.map(|tree| tree.value(basename));
319 if let Some(resolved) = value.resolve_trivial(same_change) {
320 return Merge::resolved(*resolved);
321 }
322 value
323 }
324
325 async fn sub_tree(&self, name: &RepoPathComponent) -> BackendResult<Option<Self>> {
326 let store = self.first().store();
327 match self.value(name).into_resolved() {
328 Ok(Some(TreeValue::Tree(sub_tree_id))) => {
329 let subdir = self.dir().join(name);
330 Ok(Some(Self::resolved(
331 store.get_tree(subdir, sub_tree_id).await?,
332 )))
333 }
334 Ok(_) => Ok(None),
335 Err(merge) => {
336 if !merge.is_tree() {
337 return Ok(None);
338 }
339 let trees = merge
340 .try_map_async(async |value| match value {
341 Some(TreeValue::Tree(sub_tree_id)) => {
342 let subdir = self.dir().join(name);
343 store.get_tree(subdir, sub_tree_id).await
344 }
345 Some(_) => unreachable!(),
346 None => {
347 let subdir = self.dir().join(name);
348 Ok(Tree::empty(store.clone(), subdir))
349 }
350 })
351 .await?;
352 Ok(Some(trees))
353 }
354 }
355 }
356
357 async fn sub_tree_recursive(&self, path: &RepoPath) -> BackendResult<Option<Self>> {
358 let mut current_tree = self.clone();
359 for name in path.components() {
360 match current_tree.sub_tree(name).await? {
361 None => {
362 return Ok(None);
363 }
364 Some(sub_tree) => {
365 current_tree = sub_tree;
366 }
367 }
368 }
369 Ok(Some(current_tree))
370 }
371}