##// END OF EJS Templates
dirstate-tree: Add add_file, remove_file, and drop_file...
Simon Sapin -
r47877:7dfc598d default
parent child Browse files
Show More
@@ -1,609 +1,642 b''
1 use bytes_cast::BytesCast;
1 use bytes_cast::BytesCast;
2 use std::path::PathBuf;
2 use std::path::PathBuf;
3 use std::{collections::BTreeMap, convert::TryInto};
3 use std::{collections::BTreeMap, convert::TryInto};
4
4
5 use super::path_with_basename::WithBasename;
5 use super::path_with_basename::WithBasename;
6 use crate::dirstate::parsers::clear_ambiguous_mtime;
6 use crate::dirstate::parsers::clear_ambiguous_mtime;
7 use crate::dirstate::parsers::pack_entry;
7 use crate::dirstate::parsers::pack_entry;
8 use crate::dirstate::parsers::packed_entry_size;
8 use crate::dirstate::parsers::packed_entry_size;
9 use crate::dirstate::parsers::parse_dirstate_entries;
9 use crate::dirstate::parsers::parse_dirstate_entries;
10 use crate::dirstate::parsers::parse_dirstate_parents;
10 use crate::dirstate::parsers::parse_dirstate_parents;
11 use crate::dirstate::parsers::Timestamp;
11 use crate::dirstate::parsers::Timestamp;
12 use crate::matchers::Matcher;
12 use crate::matchers::Matcher;
13 use crate::revlog::node::NULL_NODE;
13 use crate::revlog::node::NULL_NODE;
14 use crate::utils::hg_path::{HgPath, HgPathBuf};
14 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 use crate::CopyMapIter;
15 use crate::CopyMapIter;
16 use crate::DirstateEntry;
16 use crate::DirstateEntry;
17 use crate::DirstateError;
17 use crate::DirstateError;
18 use crate::DirstateMapError;
18 use crate::DirstateMapError;
19 use crate::DirstateParents;
19 use crate::DirstateParents;
20 use crate::DirstateStatus;
20 use crate::DirstateStatus;
21 use crate::EntryState;
21 use crate::EntryState;
22 use crate::FastHashMap;
22 use crate::FastHashMap;
23 use crate::HgPathCow;
23 use crate::HgPathCow;
24 use crate::PatternFileWarning;
24 use crate::PatternFileWarning;
25 use crate::StateMapIter;
25 use crate::StateMapIter;
26 use crate::StatusError;
26 use crate::StatusError;
27 use crate::StatusOptions;
27 use crate::StatusOptions;
28
28
29 pub struct DirstateMap {
29 pub struct DirstateMap {
30 parents: Option<DirstateParents>,
30 parents: Option<DirstateParents>,
31 dirty_parents: bool,
31 dirty_parents: bool,
32 root: ChildNodes,
32 root: ChildNodes,
33
33
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
35 nodes_with_entry_count: usize,
35 nodes_with_entry_count: usize,
36
36
37 /// Number of nodes anywhere in the tree that have
37 /// Number of nodes anywhere in the tree that have
38 /// `.copy_source.is_some()`.
38 /// `.copy_source.is_some()`.
39 nodes_with_copy_source_count: usize,
39 nodes_with_copy_source_count: usize,
40 }
40 }
41
41
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
43 /// map key would also work: all paths in a given map have the same parent
43 /// map key would also work: all paths in a given map have the same parent
44 /// path, so comparing full paths gives the same result as comparing base
44 /// path, so comparing full paths gives the same result as comparing base
45 /// names. However `BTreeMap` would waste time always re-comparing the same
45 /// names. However `BTreeMap` would waste time always re-comparing the same
46 /// string prefix.
46 /// string prefix.
47 type ChildNodes = BTreeMap<WithBasename<HgPathBuf>, Node>;
47 type ChildNodes = BTreeMap<WithBasename<HgPathBuf>, Node>;
48
48
49 /// Represents a file or a directory
49 /// Represents a file or a directory
50 #[derive(Default)]
50 #[derive(Default)]
51 struct Node {
51 struct Node {
52 /// `None` for directories
52 /// `None` for directories
53 entry: Option<DirstateEntry>,
53 entry: Option<DirstateEntry>,
54
54
55 copy_source: Option<HgPathBuf>,
55 copy_source: Option<HgPathBuf>,
56
56
57 children: ChildNodes,
57 children: ChildNodes,
58
58
59 /// How many (non-inclusive) descendants of this node are tracked files
59 /// How many (non-inclusive) descendants of this node are tracked files
60 tracked_descendants_count: usize,
60 tracked_descendants_count: usize,
61 }
61 }
62
62
63 impl Node {
63 impl Node {
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 fn is_tracked_file(&self) -> bool {
65 fn is_tracked_file(&self) -> bool {
66 if let Some(entry) = &self.entry {
66 if let Some(entry) = &self.entry {
67 entry.state.is_tracked()
67 entry.state.is_tracked()
68 } else {
68 } else {
69 false
69 false
70 }
70 }
71 }
71 }
72 }
72 }
73
73
74 /// `(full_path, entry, copy_source)`
74 /// `(full_path, entry, copy_source)`
75 type NodeDataMut<'a> = (
75 type NodeDataMut<'a> = (
76 &'a WithBasename<HgPathBuf>,
76 &'a WithBasename<HgPathBuf>,
77 &'a mut Option<DirstateEntry>,
77 &'a mut Option<DirstateEntry>,
78 &'a mut Option<HgPathBuf>,
78 &'a mut Option<HgPathBuf>,
79 );
79 );
80
80
81 impl DirstateMap {
81 impl DirstateMap {
82 pub fn new() -> Self {
82 pub fn new() -> Self {
83 Self {
83 Self {
84 parents: None,
84 parents: None,
85 dirty_parents: false,
85 dirty_parents: false,
86 root: ChildNodes::new(),
86 root: ChildNodes::new(),
87 nodes_with_entry_count: 0,
87 nodes_with_entry_count: 0,
88 nodes_with_copy_source_count: 0,
88 nodes_with_copy_source_count: 0,
89 }
89 }
90 }
90 }
91
91
92 fn get_node(&self, path: &HgPath) -> Option<&Node> {
92 fn get_node(&self, path: &HgPath) -> Option<&Node> {
93 let mut children = &self.root;
93 let mut children = &self.root;
94 let mut components = path.components();
94 let mut components = path.components();
95 let mut component =
95 let mut component =
96 components.next().expect("expected at least one components");
96 components.next().expect("expected at least one components");
97 loop {
97 loop {
98 let child = children.get(component)?;
98 let child = children.get(component)?;
99 if let Some(next_component) = components.next() {
99 if let Some(next_component) = components.next() {
100 component = next_component;
100 component = next_component;
101 children = &child.children;
101 children = &child.children;
102 } else {
102 } else {
103 return Some(child);
103 return Some(child);
104 }
104 }
105 }
105 }
106 }
106 }
107
107
108 /// Returns a mutable reference to the node at `path` if it exists
108 /// Returns a mutable reference to the node at `path` if it exists
109 ///
109 ///
110 /// This takes `root` instead of `&mut self` so that callers can mutate
110 /// This takes `root` instead of `&mut self` so that callers can mutate
111 /// other fields while the returned borrow is still valid
111 /// other fields while the returned borrow is still valid
112 fn get_node_mut<'tree>(
112 fn get_node_mut<'tree>(
113 root: &'tree mut ChildNodes,
113 root: &'tree mut ChildNodes,
114 path: &HgPath,
114 path: &HgPath,
115 ) -> Option<&'tree mut Node> {
115 ) -> Option<&'tree mut Node> {
116 Self::each_and_get(root, path, |_| {})
116 Self::each_and_get(root, path, |_| {})
117 }
117 }
118
118
119 /// Call `each` for each ancestor node of the one at `path` (not including
119 /// Call `each` for each ancestor node of the one at `path` (not including
120 /// that node itself), starting from nearest the root.
120 /// that node itself), starting from nearest the root.
121 ///
121 ///
122 /// Panics (possibly after some calls to `each`) if there is no node at
122 /// Panics (possibly after some calls to `each`) if there is no node at
123 /// `path`.
123 /// `path`.
124 fn for_each_ancestor_node<'tree>(
124 fn for_each_ancestor_node<'tree>(
125 &mut self,
125 &mut self,
126 path: &HgPath,
126 path: &HgPath,
127 each: impl FnMut(&mut Node),
127 each: impl FnMut(&mut Node),
128 ) {
128 ) {
129 let parent = path.parent();
129 let parent = path.parent();
130 if !parent.is_empty() {
130 if !parent.is_empty() {
131 Self::each_and_get(&mut self.root, parent, each)
131 Self::each_and_get(&mut self.root, parent, each)
132 .expect("missing dirstate node");
132 .expect("missing dirstate node");
133 }
133 }
134 }
134 }
135
135
136 /// Common implementation detail of `get_node_mut` and
136 /// Common implementation detail of `get_node_mut` and
137 /// `for_each_ancestor_node`
137 /// `for_each_ancestor_node`
138 fn each_and_get<'tree>(
138 fn each_and_get<'tree>(
139 root: &'tree mut ChildNodes,
139 root: &'tree mut ChildNodes,
140 path: &HgPath,
140 path: &HgPath,
141 mut each: impl FnMut(&mut Node),
141 mut each: impl FnMut(&mut Node),
142 ) -> Option<&'tree mut Node> {
142 ) -> Option<&'tree mut Node> {
143 let mut children = root;
143 let mut children = root;
144 let mut components = path.components();
144 let mut components = path.components();
145 let mut component =
145 let mut component =
146 components.next().expect("expected at least one components");
146 components.next().expect("expected at least one components");
147 loop {
147 loop {
148 let child = children.get_mut(component)?;
148 let child = children.get_mut(component)?;
149 each(child);
149 each(child);
150 if let Some(next_component) = components.next() {
150 if let Some(next_component) = components.next() {
151 component = next_component;
151 component = next_component;
152 children = &mut child.children;
152 children = &mut child.children;
153 } else {
153 } else {
154 return Some(child);
154 return Some(child);
155 }
155 }
156 }
156 }
157 }
157 }
158
158
159 fn get_or_insert_node<'tree>(
159 fn get_or_insert_node<'tree>(
160 root: &'tree mut ChildNodes,
160 root: &'tree mut ChildNodes,
161 path: &HgPath,
161 path: &HgPath,
162 ) -> &'tree mut Node {
162 ) -> &'tree mut Node {
163 let mut child_nodes = root;
163 let mut child_nodes = root;
164 let mut inclusive_ancestor_paths =
164 let mut inclusive_ancestor_paths =
165 WithBasename::inclusive_ancestors_of(path);
165 WithBasename::inclusive_ancestors_of(path);
166 let mut ancestor_path = inclusive_ancestor_paths
166 let mut ancestor_path = inclusive_ancestor_paths
167 .next()
167 .next()
168 .expect("expected at least one inclusive ancestor");
168 .expect("expected at least one inclusive ancestor");
169 loop {
169 loop {
170 // TODO: can we avoid double lookup in all cases without allocating
170 // TODO: can we avoid double lookup in all cases without allocating
171 // an owned key in cases where the map already contains that key?
171 // an owned key in cases where the map already contains that key?
172 let child_node =
172 let child_node =
173 if child_nodes.contains_key(ancestor_path.base_name()) {
173 if child_nodes.contains_key(ancestor_path.base_name()) {
174 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
174 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
175 } else {
175 } else {
176 // This is always a vacant entry, using `.entry()` lets us
176 // This is always a vacant entry, using `.entry()` lets us
177 // return a `&mut Node` of the newly-inserted node without
177 // return a `&mut Node` of the newly-inserted node without
178 // yet another lookup. `BTreeMap::insert` doesn’t do this.
178 // yet another lookup. `BTreeMap::insert` doesn’t do this.
179 child_nodes.entry(ancestor_path.to_owned()).or_default()
179 child_nodes.entry(ancestor_path.to_owned()).or_default()
180 };
180 };
181 if let Some(next) = inclusive_ancestor_paths.next() {
181 if let Some(next) = inclusive_ancestor_paths.next() {
182 ancestor_path = next;
182 ancestor_path = next;
183 child_nodes = &mut child_node.children;
183 child_nodes = &mut child_node.children;
184 } else {
184 } else {
185 return child_node;
185 return child_node;
186 }
186 }
187 }
187 }
188 }
188 }
189
189
190 /// The meaning of `new_copy_source` is:
190 /// The meaning of `new_copy_source` is:
191 ///
191 ///
192 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
192 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
193 /// * `Some(None)`: set `Node::copy_source` to `None`
193 /// * `Some(None)`: set `Node::copy_source` to `None`
194 /// * `None`: leave `Node::copy_source` unchanged
194 /// * `None`: leave `Node::copy_source` unchanged
195 fn add_file_node(
195 fn add_file_node(
196 &mut self,
196 &mut self,
197 path: &HgPath,
197 path: &HgPath,
198 new_entry: DirstateEntry,
198 new_entry: DirstateEntry,
199 new_copy_source: Option<Option<HgPathBuf>>,
199 new_copy_source: Option<Option<HgPathBuf>>,
200 ) {
200 ) {
201 let node = Self::get_or_insert_node(&mut self.root, path);
201 let node = Self::get_or_insert_node(&mut self.root, path);
202 if node.entry.is_none() {
202 if node.entry.is_none() {
203 self.nodes_with_entry_count += 1
203 self.nodes_with_entry_count += 1
204 }
204 }
205 if let Some(source) = &new_copy_source {
205 if let Some(source) = &new_copy_source {
206 if node.copy_source.is_none() && source.is_some() {
206 if node.copy_source.is_none() && source.is_some() {
207 self.nodes_with_copy_source_count += 1
207 self.nodes_with_copy_source_count += 1
208 }
208 }
209 if node.copy_source.is_some() && source.is_none() {
209 if node.copy_source.is_some() && source.is_none() {
210 self.nodes_with_copy_source_count -= 1
210 self.nodes_with_copy_source_count -= 1
211 }
211 }
212 }
212 }
213 let tracked_count_increment =
213 let tracked_count_increment =
214 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
214 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
215 (false, true) => 1,
215 (false, true) => 1,
216 (true, false) => -1,
216 (true, false) => -1,
217 _ => 0,
217 _ => 0,
218 };
218 };
219
219
220 node.entry = Some(new_entry);
220 node.entry = Some(new_entry);
221 if let Some(source) = new_copy_source {
221 if let Some(source) = new_copy_source {
222 node.copy_source = source
222 node.copy_source = source
223 }
223 }
224 // Borrow of `self.root` through `node` ends here
224 // Borrow of `self.root` through `node` ends here
225
225
226 match tracked_count_increment {
226 match tracked_count_increment {
227 1 => self.for_each_ancestor_node(path, |node| {
227 1 => self.for_each_ancestor_node(path, |node| {
228 node.tracked_descendants_count += 1
228 node.tracked_descendants_count += 1
229 }),
229 }),
230 // We can’t use `+= -1` because the counter is unsigned
230 // We can’t use `+= -1` because the counter is unsigned
231 -1 => self.for_each_ancestor_node(path, |node| {
231 -1 => self.for_each_ancestor_node(path, |node| {
232 node.tracked_descendants_count -= 1
232 node.tracked_descendants_count -= 1
233 }),
233 }),
234 _ => {}
234 _ => {}
235 }
235 }
236 }
236 }
237
237
238 fn iter_nodes<'a>(
238 fn iter_nodes<'a>(
239 &'a self,
239 &'a self,
240 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
240 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
241 {
241 {
242 // Depth first tree traversal.
242 // Depth first tree traversal.
243 //
243 //
244 // If we could afford internal iteration and recursion,
244 // If we could afford internal iteration and recursion,
245 // this would look like:
245 // this would look like:
246 //
246 //
247 // ```
247 // ```
248 // fn traverse_children(
248 // fn traverse_children(
249 // children: &ChildNodes,
249 // children: &ChildNodes,
250 // each: &mut impl FnMut(&Node),
250 // each: &mut impl FnMut(&Node),
251 // ) {
251 // ) {
252 // for child in children.values() {
252 // for child in children.values() {
253 // traverse_children(&child.children, each);
253 // traverse_children(&child.children, each);
254 // each(child);
254 // each(child);
255 // }
255 // }
256 // }
256 // }
257 // ```
257 // ```
258 //
258 //
259 // However we want an external iterator and therefore can’t use the
259 // However we want an external iterator and therefore can’t use the
260 // call stack. Use an explicit stack instead:
260 // call stack. Use an explicit stack instead:
261 let mut stack = Vec::new();
261 let mut stack = Vec::new();
262 let mut iter = self.root.iter();
262 let mut iter = self.root.iter();
263 std::iter::from_fn(move || {
263 std::iter::from_fn(move || {
264 while let Some((key, child_node)) = iter.next() {
264 while let Some((key, child_node)) = iter.next() {
265 // Pseudo-recursion
265 // Pseudo-recursion
266 let new_iter = child_node.children.iter();
266 let new_iter = child_node.children.iter();
267 let old_iter = std::mem::replace(&mut iter, new_iter);
267 let old_iter = std::mem::replace(&mut iter, new_iter);
268 stack.push((key, child_node, old_iter));
268 stack.push((key, child_node, old_iter));
269 }
269 }
270 // Found the end of a `children.iter()` iterator.
270 // Found the end of a `children.iter()` iterator.
271 if let Some((key, child_node, next_iter)) = stack.pop() {
271 if let Some((key, child_node, next_iter)) = stack.pop() {
272 // "Return" from pseudo-recursion by restoring state from the
272 // "Return" from pseudo-recursion by restoring state from the
273 // explicit stack
273 // explicit stack
274 iter = next_iter;
274 iter = next_iter;
275
275
276 Some((key, child_node))
276 Some((key, child_node))
277 } else {
277 } else {
278 // Reached the bottom of the stack, we’re done
278 // Reached the bottom of the stack, we’re done
279 None
279 None
280 }
280 }
281 })
281 })
282 }
282 }
283
283
284 /// Mutable iterator for the `(entry, copy source)` of each node.
284 /// Mutable iterator for the `(entry, copy source)` of each node.
285 ///
285 ///
286 /// It would not be safe to yield mutable references to nodes themeselves
286 /// It would not be safe to yield mutable references to nodes themeselves
287 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
287 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
288 /// reachable from their ancestor nodes, potentially creating multiple
288 /// reachable from their ancestor nodes, potentially creating multiple
289 /// `&mut` references to a given node.
289 /// `&mut` references to a given node.
290 fn iter_node_data_mut<'a>(
290 fn iter_node_data_mut<'a>(
291 &'a mut self,
291 &'a mut self,
292 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
292 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
293 // Explict stack for pseudo-recursion, see `iter_nodes` above.
293 // Explict stack for pseudo-recursion, see `iter_nodes` above.
294 let mut stack = Vec::new();
294 let mut stack = Vec::new();
295 let mut iter = self.root.iter_mut();
295 let mut iter = self.root.iter_mut();
296 std::iter::from_fn(move || {
296 std::iter::from_fn(move || {
297 while let Some((key, child_node)) = iter.next() {
297 while let Some((key, child_node)) = iter.next() {
298 // Pseudo-recursion
298 // Pseudo-recursion
299 let data =
299 let data =
300 (key, &mut child_node.entry, &mut child_node.copy_source);
300 (key, &mut child_node.entry, &mut child_node.copy_source);
301 let new_iter = child_node.children.iter_mut();
301 let new_iter = child_node.children.iter_mut();
302 let old_iter = std::mem::replace(&mut iter, new_iter);
302 let old_iter = std::mem::replace(&mut iter, new_iter);
303 stack.push((data, old_iter));
303 stack.push((data, old_iter));
304 }
304 }
305 // Found the end of a `children.values_mut()` iterator.
305 // Found the end of a `children.values_mut()` iterator.
306 if let Some((data, next_iter)) = stack.pop() {
306 if let Some((data, next_iter)) = stack.pop() {
307 // "Return" from pseudo-recursion by restoring state from the
307 // "Return" from pseudo-recursion by restoring state from the
308 // explicit stack
308 // explicit stack
309 iter = next_iter;
309 iter = next_iter;
310
310
311 Some(data)
311 Some(data)
312 } else {
312 } else {
313 // Reached the bottom of the stack, we’re done
313 // Reached the bottom of the stack, we’re done
314 None
314 None
315 }
315 }
316 })
316 })
317 }
317 }
318 }
318 }
319
319
320 impl super::dispatch::DirstateMapMethods for DirstateMap {
320 impl super::dispatch::DirstateMapMethods for DirstateMap {
321 fn clear(&mut self) {
321 fn clear(&mut self) {
322 self.set_parents(&DirstateParents {
322 self.set_parents(&DirstateParents {
323 p1: NULL_NODE,
323 p1: NULL_NODE,
324 p2: NULL_NODE,
324 p2: NULL_NODE,
325 });
325 });
326 self.root.clear();
326 self.root.clear();
327 self.nodes_with_entry_count = 0;
327 self.nodes_with_entry_count = 0;
328 self.nodes_with_copy_source_count = 0;
328 self.nodes_with_copy_source_count = 0;
329 }
329 }
330
330
331 fn add_file(
331 fn add_file(
332 &mut self,
332 &mut self,
333 _filename: &HgPath,
333 filename: &HgPath,
334 _old_state: EntryState,
334 _old_state: EntryState,
335 _entry: DirstateEntry,
335 entry: DirstateEntry,
336 ) -> Result<(), DirstateMapError> {
336 ) -> Result<(), DirstateMapError> {
337 todo!()
337 self.add_file_node(filename, entry, None);
338 Ok(())
338 }
339 }
339
340
340 fn remove_file(
341 fn remove_file(
341 &mut self,
342 &mut self,
342 _filename: &HgPath,
343 filename: &HgPath,
343 _old_state: EntryState,
344 _old_state: EntryState,
344 _size: i32,
345 size: i32,
345 ) -> Result<(), DirstateMapError> {
346 ) -> Result<(), DirstateMapError> {
346 todo!()
347 let entry = DirstateEntry {
348 state: EntryState::Removed,
349 mode: 0,
350 size,
351 mtime: 0,
352 };
353 self.add_file_node(filename, entry, None);
354 Ok(())
347 }
355 }
348
356
349 fn drop_file(
357 fn drop_file(
350 &mut self,
358 &mut self,
351 _filename: &HgPath,
359 filename: &HgPath,
352 _old_state: EntryState,
360 _old_state: EntryState,
353 ) -> Result<bool, DirstateMapError> {
361 ) -> Result<bool, DirstateMapError> {
354 todo!()
362 if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
363 let was_tracked = node.is_tracked_file();
364 let had_entry = node.entry.is_some();
365 let had_copy_source = node.copy_source.is_some();
366
367 // TODO: this leaves in the tree a "non-file" node. Should we
368 // remove the node instead, together with ancestor nodes for
369 // directories that become empty?
370 node.entry = None;
371 node.copy_source = None;
372
373 if had_entry {
374 self.nodes_with_entry_count -= 1
375 }
376 if had_copy_source {
377 self.nodes_with_copy_source_count -= 1
378 }
379 if was_tracked {
380 self.for_each_ancestor_node(filename, |node| {
381 node.tracked_descendants_count -= 1
382 })
383 }
384 Ok(had_entry)
385 } else {
386 Ok(false)
387 }
355 }
388 }
356
389
357 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
390 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
358 for filename in filenames {
391 for filename in filenames {
359 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
392 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
360 if let Some(entry) = node.entry.as_mut() {
393 if let Some(entry) = node.entry.as_mut() {
361 clear_ambiguous_mtime(entry, now);
394 clear_ambiguous_mtime(entry, now);
362 }
395 }
363 }
396 }
364 }
397 }
365 }
398 }
366
399
367 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
400 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
368 todo!()
401 todo!()
369 }
402 }
370
403
371 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
404 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
372 todo!()
405 todo!()
373 }
406 }
374
407
375 fn non_normal_or_other_parent_paths(
408 fn non_normal_or_other_parent_paths(
376 &mut self,
409 &mut self,
377 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
410 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
378 todo!()
411 todo!()
379 }
412 }
380
413
381 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
414 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
382 todo!()
415 todo!()
383 }
416 }
384
417
385 fn iter_non_normal_paths(
418 fn iter_non_normal_paths(
386 &mut self,
419 &mut self,
387 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
420 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
388 todo!()
421 todo!()
389 }
422 }
390
423
391 fn iter_non_normal_paths_panic(
424 fn iter_non_normal_paths_panic(
392 &self,
425 &self,
393 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
426 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
394 todo!()
427 todo!()
395 }
428 }
396
429
397 fn iter_other_parent_paths(
430 fn iter_other_parent_paths(
398 &mut self,
431 &mut self,
399 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
432 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
400 todo!()
433 todo!()
401 }
434 }
402
435
403 fn has_tracked_dir(
436 fn has_tracked_dir(
404 &mut self,
437 &mut self,
405 directory: &HgPath,
438 directory: &HgPath,
406 ) -> Result<bool, DirstateMapError> {
439 ) -> Result<bool, DirstateMapError> {
407 if let Some(node) = self.get_node(directory) {
440 if let Some(node) = self.get_node(directory) {
408 // A node without a `DirstateEntry` was created to hold child
441 // A node without a `DirstateEntry` was created to hold child
409 // nodes, and is therefore a directory.
442 // nodes, and is therefore a directory.
410 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
443 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
411 } else {
444 } else {
412 Ok(false)
445 Ok(false)
413 }
446 }
414 }
447 }
415
448
416 fn has_dir(
449 fn has_dir(
417 &mut self,
450 &mut self,
418 directory: &HgPath,
451 directory: &HgPath,
419 ) -> Result<bool, DirstateMapError> {
452 ) -> Result<bool, DirstateMapError> {
420 if let Some(node) = self.get_node(directory) {
453 if let Some(node) = self.get_node(directory) {
421 // A node without a `DirstateEntry` was created to hold child
454 // A node without a `DirstateEntry` was created to hold child
422 // nodes, and is therefore a directory.
455 // nodes, and is therefore a directory.
423 Ok(node.entry.is_none())
456 Ok(node.entry.is_none())
424 } else {
457 } else {
425 Ok(false)
458 Ok(false)
426 }
459 }
427 }
460 }
428
461
429 fn parents(
462 fn parents(
430 &mut self,
463 &mut self,
431 file_contents: &[u8],
464 file_contents: &[u8],
432 ) -> Result<&DirstateParents, DirstateError> {
465 ) -> Result<&DirstateParents, DirstateError> {
433 if self.parents.is_none() {
466 if self.parents.is_none() {
434 let parents = if !file_contents.is_empty() {
467 let parents = if !file_contents.is_empty() {
435 parse_dirstate_parents(file_contents)?.clone()
468 parse_dirstate_parents(file_contents)?.clone()
436 } else {
469 } else {
437 DirstateParents {
470 DirstateParents {
438 p1: NULL_NODE,
471 p1: NULL_NODE,
439 p2: NULL_NODE,
472 p2: NULL_NODE,
440 }
473 }
441 };
474 };
442 self.parents = Some(parents);
475 self.parents = Some(parents);
443 }
476 }
444 Ok(self.parents.as_ref().unwrap())
477 Ok(self.parents.as_ref().unwrap())
445 }
478 }
446
479
447 fn set_parents(&mut self, parents: &DirstateParents) {
480 fn set_parents(&mut self, parents: &DirstateParents) {
448 self.parents = Some(parents.clone());
481 self.parents = Some(parents.clone());
449 self.dirty_parents = true;
482 self.dirty_parents = true;
450 }
483 }
451
484
452 fn read<'a>(
485 fn read<'a>(
453 &mut self,
486 &mut self,
454 file_contents: &'a [u8],
487 file_contents: &'a [u8],
455 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
488 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
456 if file_contents.is_empty() {
489 if file_contents.is_empty() {
457 return Ok(None);
490 return Ok(None);
458 }
491 }
459
492
460 let parents = parse_dirstate_entries(
493 let parents = parse_dirstate_entries(
461 file_contents,
494 file_contents,
462 |path, entry, copy_source| {
495 |path, entry, copy_source| {
463 self.add_file_node(
496 self.add_file_node(
464 path,
497 path,
465 *entry,
498 *entry,
466 Some(copy_source.map(HgPath::to_owned)),
499 Some(copy_source.map(HgPath::to_owned)),
467 )
500 )
468 },
501 },
469 )?;
502 )?;
470
503
471 if !self.dirty_parents {
504 if !self.dirty_parents {
472 self.set_parents(parents);
505 self.set_parents(parents);
473 }
506 }
474
507
475 Ok(Some(parents))
508 Ok(Some(parents))
476 }
509 }
477
510
478 fn pack(
511 fn pack(
479 &mut self,
512 &mut self,
480 parents: DirstateParents,
513 parents: DirstateParents,
481 now: Timestamp,
514 now: Timestamp,
482 ) -> Result<Vec<u8>, DirstateError> {
515 ) -> Result<Vec<u8>, DirstateError> {
483 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
516 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
484 // reallocations
517 // reallocations
485 let mut size = parents.as_bytes().len();
518 let mut size = parents.as_bytes().len();
486 for (path, node) in self.iter_nodes() {
519 for (path, node) in self.iter_nodes() {
487 if node.entry.is_some() {
520 if node.entry.is_some() {
488 size += packed_entry_size(
521 size += packed_entry_size(
489 path.full_path(),
522 path.full_path(),
490 node.copy_source.as_ref(),
523 node.copy_source.as_ref(),
491 )
524 )
492 }
525 }
493 }
526 }
494
527
495 let mut packed = Vec::with_capacity(size);
528 let mut packed = Vec::with_capacity(size);
496 packed.extend(parents.as_bytes());
529 packed.extend(parents.as_bytes());
497
530
498 let now: i32 = now.0.try_into().expect("time overflow");
531 let now: i32 = now.0.try_into().expect("time overflow");
499 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
532 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
500 if let Some(entry) = opt_entry {
533 if let Some(entry) = opt_entry {
501 clear_ambiguous_mtime(entry, now);
534 clear_ambiguous_mtime(entry, now);
502 pack_entry(
535 pack_entry(
503 path.full_path(),
536 path.full_path(),
504 entry,
537 entry,
505 copy_source.as_ref(),
538 copy_source.as_ref(),
506 &mut packed,
539 &mut packed,
507 );
540 );
508 }
541 }
509 }
542 }
510 self.dirty_parents = false;
543 self.dirty_parents = false;
511 Ok(packed)
544 Ok(packed)
512 }
545 }
513
546
514 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
547 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
515 todo!()
548 todo!()
516 }
549 }
517
550
518 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
551 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
519 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
552 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
520 // needs to be recomputed
553 // needs to be recomputed
521 Ok(())
554 Ok(())
522 }
555 }
523
556
524 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
557 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
525 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
558 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
526 // to be recomputed
559 // to be recomputed
527 Ok(())
560 Ok(())
528 }
561 }
529
562
530 fn status<'a>(
563 fn status<'a>(
531 &'a self,
564 &'a self,
532 _matcher: &'a (dyn Matcher + Sync),
565 _matcher: &'a (dyn Matcher + Sync),
533 _root_dir: PathBuf,
566 _root_dir: PathBuf,
534 _ignore_files: Vec<PathBuf>,
567 _ignore_files: Vec<PathBuf>,
535 _options: StatusOptions,
568 _options: StatusOptions,
536 ) -> Result<
569 ) -> Result<
537 (
570 (
538 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
571 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
539 Vec<PatternFileWarning>,
572 Vec<PatternFileWarning>,
540 ),
573 ),
541 StatusError,
574 StatusError,
542 > {
575 > {
543 todo!()
576 todo!()
544 }
577 }
545
578
546 fn copy_map_len(&self) -> usize {
579 fn copy_map_len(&self) -> usize {
547 self.nodes_with_copy_source_count
580 self.nodes_with_copy_source_count
548 }
581 }
549
582
550 fn copy_map_iter(&self) -> CopyMapIter<'_> {
583 fn copy_map_iter(&self) -> CopyMapIter<'_> {
551 Box::new(self.iter_nodes().filter_map(|(path, node)| {
584 Box::new(self.iter_nodes().filter_map(|(path, node)| {
552 node.copy_source
585 node.copy_source
553 .as_ref()
586 .as_ref()
554 .map(|copy_source| (path.full_path(), copy_source))
587 .map(|copy_source| (path.full_path(), copy_source))
555 }))
588 }))
556 }
589 }
557
590
558 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
591 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
559 if let Some(node) = self.get_node(key) {
592 if let Some(node) = self.get_node(key) {
560 node.copy_source.is_some()
593 node.copy_source.is_some()
561 } else {
594 } else {
562 false
595 false
563 }
596 }
564 }
597 }
565
598
566 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
599 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
567 self.get_node(key)?.copy_source.as_ref()
600 self.get_node(key)?.copy_source.as_ref()
568 }
601 }
569
602
570 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
603 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
571 let count = &mut self.nodes_with_copy_source_count;
604 let count = &mut self.nodes_with_copy_source_count;
572 Self::get_node_mut(&mut self.root, key).and_then(|node| {
605 Self::get_node_mut(&mut self.root, key).and_then(|node| {
573 if node.copy_source.is_some() {
606 if node.copy_source.is_some() {
574 *count -= 1
607 *count -= 1
575 }
608 }
576 node.copy_source.take()
609 node.copy_source.take()
577 })
610 })
578 }
611 }
579
612
580 fn copy_map_insert(
613 fn copy_map_insert(
581 &mut self,
614 &mut self,
582 key: HgPathBuf,
615 key: HgPathBuf,
583 value: HgPathBuf,
616 value: HgPathBuf,
584 ) -> Option<HgPathBuf> {
617 ) -> Option<HgPathBuf> {
585 let node = Self::get_or_insert_node(&mut self.root, &key);
618 let node = Self::get_or_insert_node(&mut self.root, &key);
586 if node.copy_source.is_none() {
619 if node.copy_source.is_none() {
587 self.nodes_with_copy_source_count += 1
620 self.nodes_with_copy_source_count += 1
588 }
621 }
589 node.copy_source.replace(value)
622 node.copy_source.replace(value)
590 }
623 }
591
624
592 fn len(&self) -> usize {
625 fn len(&self) -> usize {
593 self.nodes_with_entry_count
626 self.nodes_with_entry_count
594 }
627 }
595
628
596 fn contains_key(&self, key: &HgPath) -> bool {
629 fn contains_key(&self, key: &HgPath) -> bool {
597 self.get(key).is_some()
630 self.get(key).is_some()
598 }
631 }
599
632
600 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
633 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
601 self.get_node(key)?.entry.as_ref()
634 self.get_node(key)?.entry.as_ref()
602 }
635 }
603
636
604 fn iter(&self) -> StateMapIter<'_> {
637 fn iter(&self) -> StateMapIter<'_> {
605 Box::new(self.iter_nodes().filter_map(|(path, node)| {
638 Box::new(self.iter_nodes().filter_map(|(path, node)| {
606 node.entry.as_ref().map(|entry| (path.full_path(), entry))
639 node.entry.as_ref().map(|entry| (path.full_path(), entry))
607 }))
640 }))
608 }
641 }
609 }
642 }
General Comments 0
You need to be logged in to leave comments. Login now