Mercurial > hg
comparison rust/hg-core/src/dirstate_tree/dirstate_map.rs @ 47192:1249eb9cc332
dirstate-tree: Refactor DirstateMap::drop_file to be recursive
It should behave the same as before. This will enable the next changeset
to run code on the way "down" (in order to removing newly-empty nodes).
Differential Revision: https://phab.mercurial-scm.org/D10705
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 10 May 2021 21:31:05 +0200 |
parents | ecfe0819ada5 |
children | 47ccab19bf9f |
comparison
equal
deleted
inserted
replaced
47191:b338d831d18c | 47192:1249eb9cc332 |
---|---|
151 /// other fields while the returned borrow is still valid | 151 /// other fields while the returned borrow is still valid |
152 fn get_node_mut<'tree>( | 152 fn get_node_mut<'tree>( |
153 root: &'tree mut ChildNodes<'on_disk>, | 153 root: &'tree mut ChildNodes<'on_disk>, |
154 path: &HgPath, | 154 path: &HgPath, |
155 ) -> Option<&'tree mut Node<'on_disk>> { | 155 ) -> Option<&'tree mut Node<'on_disk>> { |
156 Self::get_node_mut_tracing_ancestors(root, path, |_| {}) | |
157 } | |
158 | |
159 /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of | |
160 /// the node. | |
161 /// | |
162 /// Note that `each_ancestor` may be called (with what would be ancestors) | |
163 /// even if it turns out there is no node at `path`. | |
164 fn get_node_mut_tracing_ancestors<'tree>( | |
165 root: &'tree mut ChildNodes<'on_disk>, | |
166 path: &HgPath, | |
167 mut each_ancestor: impl FnMut(&mut Node), | |
168 ) -> Option<&'tree mut Node<'on_disk>> { | |
169 let mut children = root; | 156 let mut children = root; |
170 let mut components = path.components(); | 157 let mut components = path.components(); |
171 let mut component = | 158 let mut component = |
172 components.next().expect("expected at least one components"); | 159 components.next().expect("expected at least one components"); |
173 loop { | 160 loop { |
174 let child = children.get_mut(component)?; | 161 let child = children.get_mut(component)?; |
175 if let Some(next_component) = components.next() { | 162 if let Some(next_component) = components.next() { |
176 each_ancestor(child); | |
177 component = next_component; | 163 component = next_component; |
178 children = &mut child.children; | 164 children = &mut child.children; |
179 } else { | 165 } else { |
180 return Some(child); | 166 return Some(child); |
181 } | 167 } |
367 fn drop_file( | 353 fn drop_file( |
368 &mut self, | 354 &mut self, |
369 filename: &HgPath, | 355 filename: &HgPath, |
370 old_state: EntryState, | 356 old_state: EntryState, |
371 ) -> Result<bool, DirstateMapError> { | 357 ) -> Result<bool, DirstateMapError> { |
372 let was_tracked = old_state.is_tracked(); | 358 struct Dropped { |
373 if let Some(node) = Self::get_node_mut_tracing_ancestors( | 359 was_tracked: bool, |
374 &mut self.root, | 360 had_entry: bool, |
375 filename, | 361 had_copy_source: bool, |
376 |ancestor| { | 362 } |
377 if was_tracked { | 363 fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> { |
378 ancestor.tracked_descendants_count -= 1 | 364 let (first_path_component, rest_of_path) = |
365 path.split_first_component(); | |
366 let node = nodes.get_mut(first_path_component)?; | |
367 let dropped; | |
368 if let Some(rest) = rest_of_path { | |
369 dropped = recur(&mut node.children, rest)?; | |
370 if dropped.was_tracked { | |
371 node.tracked_descendants_count -= 1; | |
379 } | 372 } |
380 }, | 373 } else { |
381 ) { | 374 dropped = Dropped { |
382 let had_entry = node.entry.is_some(); | 375 was_tracked: node |
383 let had_copy_source = node.copy_source.is_some(); | 376 .entry |
384 | 377 .as_ref() |
385 // TODO: this leaves in the tree a "non-file" node. Should we | 378 .map_or(false, |entry| entry.state.is_tracked()), |
386 // remove the node instead, together with ancestor nodes for | 379 had_entry: node.entry.take().is_some(), |
387 // directories that become empty? | 380 had_copy_source: node.copy_source.take().is_some(), |
388 node.entry = None; | 381 }; |
389 node.copy_source = None; | 382 // TODO: this leaves in the tree a "non-file" node. Should we |
390 | 383 // remove the node instead, together with ancestor nodes for |
391 if had_entry { | 384 // directories that become empty? |
385 } | |
386 Some(dropped) | |
387 } | |
388 | |
389 if let Some(dropped) = recur(&mut self.root, filename) { | |
390 if dropped.had_entry { | |
392 self.nodes_with_entry_count -= 1 | 391 self.nodes_with_entry_count -= 1 |
393 } | 392 } |
394 if had_copy_source { | 393 if dropped.had_copy_source { |
395 self.nodes_with_copy_source_count -= 1 | 394 self.nodes_with_copy_source_count -= 1 |
396 } | 395 } |
397 Ok(had_entry) | 396 Ok(dropped.had_entry) |
398 } else { | 397 } else { |
399 assert!(!was_tracked); | 398 debug_assert!(!old_state.is_tracked()); |
400 Ok(false) | 399 Ok(false) |
401 } | 400 } |
402 } | 401 } |
403 | 402 |
404 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { | 403 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { |