##// END OF EJS Templates
dirstate-tree: Add has_dir and has_tracked_dir...
Simon Sapin -
r47876:52906934 default
parent child Browse files
Show More
@@ -66,6 +66,16 b' pub enum EntryState {'
66 66 Unknown,
67 67 }
68 68
69 impl EntryState {
70 pub fn is_tracked(self) -> bool {
71 use EntryState::*;
72 match self {
73 Normal | Added | Merged => true,
74 Removed | Unknown => false,
75 }
76 }
77 }
78
69 79 impl TryFrom<u8> for EntryState {
70 80 type Error = HgError;
71 81
@@ -46,11 +46,29 b' pub struct DirstateMap {'
46 46 /// string prefix.
47 47 type ChildNodes = BTreeMap<WithBasename<HgPathBuf>, Node>;
48 48
49 /// Represents a file or a directory
49 50 #[derive(Default)]
50 51 struct Node {
52 /// `None` for directories
51 53 entry: Option<DirstateEntry>,
54
52 55 copy_source: Option<HgPathBuf>,
56
53 57 children: ChildNodes,
58
59 /// How many (non-inclusive) descendants of this node are tracked files
60 tracked_descendants_count: usize,
61 }
62
63 impl Node {
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 fn is_tracked_file(&self) -> bool {
66 if let Some(entry) = &self.entry {
67 entry.state.is_tracked()
68 } else {
69 false
70 }
71 }
54 72 }
55 73
56 74 /// `(full_path, entry, copy_source)`
@@ -87,18 +105,48 b' impl DirstateMap {'
87 105 }
88 106 }
89 107
108 /// Returns a mutable reference to the node at `path` if it exists
109 ///
90 110 /// This takes `root` instead of `&mut self` so that callers can mutate
91 111 /// other fields while the returned borrow is still valid
92 112 fn get_node_mut<'tree>(
93 113 root: &'tree mut ChildNodes,
94 114 path: &HgPath,
95 115 ) -> Option<&'tree mut Node> {
116 Self::each_and_get(root, path, |_| {})
117 }
118
119 /// Call `each` for each ancestor node of the one at `path` (not including
120 /// that node itself), starting from nearest the root.
121 ///
122 /// Panics (possibly after some calls to `each`) if there is no node at
123 /// `path`.
124 fn for_each_ancestor_node<'tree>(
125 &mut self,
126 path: &HgPath,
127 each: impl FnMut(&mut Node),
128 ) {
129 let parent = path.parent();
130 if !parent.is_empty() {
131 Self::each_and_get(&mut self.root, parent, each)
132 .expect("missing dirstate node");
133 }
134 }
135
136 /// Common implementation detail of `get_node_mut` and
137 /// `for_each_ancestor_node`
138 fn each_and_get<'tree>(
139 root: &'tree mut ChildNodes,
140 path: &HgPath,
141 mut each: impl FnMut(&mut Node),
142 ) -> Option<&'tree mut Node> {
96 143 let mut children = root;
97 144 let mut components = path.components();
98 145 let mut component =
99 146 components.next().expect("expected at least one components");
100 147 loop {
101 148 let child = children.get_mut(component)?;
149 each(child);
102 150 if let Some(next_component) = components.next() {
103 151 component = next_component;
104 152 children = &mut child.children;
@@ -162,10 +210,29 b' impl DirstateMap {'
162 210 self.nodes_with_copy_source_count -= 1
163 211 }
164 212 }
213 let tracked_count_increment =
214 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
215 (false, true) => 1,
216 (true, false) => -1,
217 _ => 0,
218 };
219
165 220 node.entry = Some(new_entry);
166 221 if let Some(source) = new_copy_source {
167 222 node.copy_source = source
168 223 }
224 // Borrow of `self.root` through `node` ends here
225
226 match tracked_count_increment {
227 1 => self.for_each_ancestor_node(path, |node| {
228 node.tracked_descendants_count += 1
229 }),
230 // We can’t use `+= -1` because the counter is unsigned
231 -1 => self.for_each_ancestor_node(path, |node| {
232 node.tracked_descendants_count -= 1
233 }),
234 _ => {}
235 }
169 236 }
170 237
171 238 fn iter_nodes<'a>(
@@ -335,16 +402,28 b' impl super::dispatch::DirstateMapMethods'
335 402
336 403 fn has_tracked_dir(
337 404 &mut self,
338 _directory: &HgPath,
405 directory: &HgPath,
339 406 ) -> Result<bool, DirstateMapError> {
340 todo!()
407 if let Some(node) = self.get_node(directory) {
408 // A node without a `DirstateEntry` was created to hold child
409 // nodes, and is therefore a directory.
410 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
411 } else {
412 Ok(false)
413 }
341 414 }
342 415
343 416 fn has_dir(
344 417 &mut self,
345 _directory: &HgPath,
418 directory: &HgPath,
346 419 ) -> Result<bool, DirstateMapError> {
347 todo!()
420 if let Some(node) = self.get_node(directory) {
421 // A node without a `DirstateEntry` was created to hold child
422 // nodes, and is therefore a directory.
423 Ok(node.entry.is_none())
424 } else {
425 Ok(false)
426 }
348 427 }
349 428
350 429 fn parents(
@@ -437,11 +516,15 b' impl super::dispatch::DirstateMapMethods'
437 516 }
438 517
439 518 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
440 todo!()
519 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
520 // needs to be recomputed
521 Ok(())
441 522 }
442 523
443 524 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
444 todo!()
525 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
526 // to be recomputed
527 Ok(())
445 528 }
446 529
447 530 fn status<'a>(
General Comments 0
You need to be logged in to leave comments. Login now