comparison rust/hg-core/src/dirstate_tree/dirstate_map.rs @ 47335:ed1583a845d2

dirstate-v2: Make more APIs fallible, returning Result When parsing becomes lazy, parse error will potentially happen in more places. This propagates such errors to callers. Differential Revision: https://phab.mercurial-scm.org/D10749
author Simon Sapin <simon.sapin@octobus.net>
date Wed, 19 May 2021 13:15:00 +0200
parents 18b3060fe598
children 8d0260d0dbc9
comparison
equal deleted inserted replaced
47334:18b3060fe598 47335:ed1583a845d2
3 use std::borrow::Cow; 3 use std::borrow::Cow;
4 use std::convert::TryInto; 4 use std::convert::TryInto;
5 use std::path::PathBuf; 5 use std::path::PathBuf;
6 6
7 use super::on_disk; 7 use super::on_disk;
8 use super::on_disk::DirstateV2ParseError;
8 use super::path_with_basename::WithBasename; 9 use super::path_with_basename::WithBasename;
9 use crate::dirstate::parsers::pack_entry; 10 use crate::dirstate::parsers::pack_entry;
10 use crate::dirstate::parsers::packed_entry_size; 11 use crate::dirstate::parsers::packed_entry_size;
11 use crate::dirstate::parsers::parse_dirstate_entries; 12 use crate::dirstate::parsers::parse_dirstate_entries;
12 use crate::dirstate::parsers::Timestamp; 13 use crate::dirstate::parsers::Timestamp;
13 use crate::matchers::Matcher; 14 use crate::matchers::Matcher;
14 use crate::utils::hg_path::{HgPath, HgPathBuf}; 15 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 use crate::CopyMapIter; 16 use crate::CopyMapIter;
16 use crate::DirstateEntry; 17 use crate::DirstateEntry;
17 use crate::DirstateError; 18 use crate::DirstateError;
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::PatternFileWarning; 23 use crate::PatternFileWarning;
79 } 79 }
80 } 80 }
81 81
82 pub(super) fn make_mut( 82 pub(super) fn make_mut(
83 &mut self, 83 &mut self,
84 ) -> &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>> { 84 ) -> Result<
85 match self { 85 &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>,
86 ChildNodes::InMemory(nodes) => nodes, 86 DirstateV2ParseError,
87 > {
88 match self {
89 ChildNodes::InMemory(nodes) => Ok(nodes),
87 } 90 }
88 } 91 }
89 } 92 }
90 93
91 impl<'tree, 'on_disk> ChildNodesRef<'tree, 'on_disk> { 94 impl<'tree, 'on_disk> ChildNodesRef<'tree, 'on_disk> {
92 pub(super) fn get( 95 pub(super) fn get(
93 &self, 96 &self,
94 base_name: &HgPath, 97 base_name: &HgPath,
95 ) -> Option<NodeRef<'tree, 'on_disk>> { 98 ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> {
96 match self { 99 match self {
97 ChildNodesRef::InMemory(nodes) => nodes 100 ChildNodesRef::InMemory(nodes) => Ok(nodes
98 .get_key_value(base_name) 101 .get_key_value(base_name)
99 .map(|(k, v)| NodeRef::InMemory(k, v)), 102 .map(|(k, v)| NodeRef::InMemory(k, v))),
100 } 103 }
101 } 104 }
102 105
103 /// Iterate in undefined order 106 /// Iterate in undefined order
104 pub(super) fn iter( 107 pub(super) fn iter(
129 ChildNodesRef::InMemory(nodes) => { 132 ChildNodesRef::InMemory(nodes) => {
130 let mut vec: Vec<_> = nodes 133 let mut vec: Vec<_> = nodes
131 .iter() 134 .iter()
132 .map(|(k, v)| NodeRef::InMemory(k, v)) 135 .map(|(k, v)| NodeRef::InMemory(k, v))
133 .collect(); 136 .collect();
137 fn sort_key<'a>(node: &'a NodeRef) -> &'a HgPath {
138 match node {
139 NodeRef::InMemory(path, _node) => path.base_name(),
140 }
141 }
134 // `sort_unstable_by_key` doesn’t allow keys borrowing from the 142 // `sort_unstable_by_key` doesn’t allow keys borrowing from the
135 // value: https://github.com/rust-lang/rust/issues/34162 143 // value: https://github.com/rust-lang/rust/issues/34162
136 vec.sort_unstable_by(|a, b| a.base_name().cmp(b.base_name())); 144 vec.sort_unstable_by(|a, b| sort_key(a).cmp(sort_key(b)));
137 vec 145 vec
138 } 146 }
139 } 147 }
140 } 148 }
141 } 149 }
142 150
143 impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> { 151 impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> {
144 pub(super) fn full_path(&self) -> &'tree HgPath { 152 pub(super) fn full_path(
145 match self { 153 &self,
146 NodeRef::InMemory(path, _node) => path.full_path(), 154 ) -> Result<&'tree HgPath, DirstateV2ParseError> {
155 match self {
156 NodeRef::InMemory(path, _node) => Ok(path.full_path()),
147 } 157 }
148 } 158 }
149 159
150 /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree 160 /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree
151 pub(super) fn full_path_cow(&self) -> Cow<'on_disk, HgPath> { 161 pub(super) fn full_path_cow(
152 match self { 162 &self,
153 NodeRef::InMemory(path, _node) => path.full_path().clone(), 163 ) -> Result<Cow<'on_disk, HgPath>, DirstateV2ParseError> {
154 } 164 match self {
155 } 165 NodeRef::InMemory(path, _node) => Ok(path.full_path().clone()),
156 166 }
157 pub(super) fn base_name(&self) -> &'tree HgPath { 167 }
158 match self { 168
159 NodeRef::InMemory(path, _node) => path.base_name(), 169 pub(super) fn base_name(
160 } 170 &self,
161 } 171 ) -> Result<&'tree HgPath, DirstateV2ParseError> {
162 172 match self {
163 pub(super) fn children(&self) -> ChildNodesRef<'tree, 'on_disk> { 173 NodeRef::InMemory(path, _node) => Ok(path.base_name()),
164 match self { 174 }
165 NodeRef::InMemory(_path, node) => node.children.as_ref(), 175 }
166 } 176
167 } 177 pub(super) fn children(
168 178 &self,
169 pub(super) fn copy_source(&self) -> Option<&'tree HgPath> { 179 ) -> Result<ChildNodesRef<'tree, 'on_disk>, DirstateV2ParseError> {
180 match self {
181 NodeRef::InMemory(_path, node) => Ok(node.children.as_ref()),
182 }
183 }
184
185 pub(super) fn has_copy_source(&self) -> bool {
186 match self {
187 NodeRef::InMemory(_path, node) => node.copy_source.is_some(),
188 }
189 }
190
191 pub(super) fn copy_source(
192 &self,
193 ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> {
170 match self { 194 match self {
171 NodeRef::InMemory(_path, node) => { 195 NodeRef::InMemory(_path, node) => {
172 node.copy_source.as_ref().map(|s| &**s) 196 Ok(node.copy_source.as_ref().map(|s| &**s))
173 } 197 }
174 } 198 }
175 } 199 }
176 200
177 pub(super) fn has_entry(&self) -> bool { 201 pub(super) fn has_entry(&self) -> bool {
178 match self { 202 match self {
179 NodeRef::InMemory(_path, node) => node.entry.is_some(), 203 NodeRef::InMemory(_path, node) => node.entry.is_some(),
180 } 204 }
181 } 205 }
182 206
183 pub(super) fn entry(&self) -> Option<DirstateEntry> { 207 pub(super) fn entry(
184 match self { 208 &self,
185 NodeRef::InMemory(_path, node) => node.entry, 209 ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
186 } 210 match self {
187 } 211 NodeRef::InMemory(_path, node) => Ok(node.entry),
188 pub(super) fn state(&self) -> Option<EntryState> { 212 }
213 }
214
215 pub(super) fn state(
216 &self,
217 ) -> Result<Option<EntryState>, DirstateV2ParseError> {
189 match self { 218 match self {
190 NodeRef::InMemory(_path, node) => { 219 NodeRef::InMemory(_path, node) => {
191 node.entry.as_ref().map(|entry| entry.state) 220 Ok(node.entry.as_ref().map(|entry| entry.state))
192 } 221 }
193 } 222 }
194 } 223 }
195 224
196 pub(super) fn tracked_descendants_count(&self) -> u32 { 225 pub(super) fn tracked_descendants_count(&self) -> u32 {
251 |ancestor| { 280 |ancestor| {
252 if tracked { 281 if tracked {
253 ancestor.tracked_descendants_count += 1 282 ancestor.tracked_descendants_count += 1
254 } 283 }
255 }, 284 },
256 ); 285 )?;
257 assert!( 286 assert!(
258 node.entry.is_none(), 287 node.entry.is_none(),
259 "duplicate dirstate entry in read" 288 "duplicate dirstate entry in read"
260 ); 289 );
261 assert!( 290 assert!(
266 node.copy_source = copy_source.map(Cow::Borrowed); 295 node.copy_source = copy_source.map(Cow::Borrowed);
267 map.nodes_with_entry_count += 1; 296 map.nodes_with_entry_count += 1;
268 if copy_source.is_some() { 297 if copy_source.is_some() {
269 map.nodes_with_copy_source_count += 1 298 map.nodes_with_copy_source_count += 1
270 } 299 }
300 Ok(())
271 }, 301 },
272 )?; 302 )?;
273 let parents = Some(parents.clone()); 303 let parents = Some(parents.clone());
274 304
275 Ok((map, parents)) 305 Ok((map, parents))
276 } 306 }
277 307
278 fn get_node<'tree>( 308 fn get_node<'tree>(
279 &'tree self, 309 &'tree self,
280 path: &HgPath, 310 path: &HgPath,
281 ) -> Option<NodeRef<'tree, 'on_disk>> { 311 ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> {
282 let mut children = self.root.as_ref(); 312 let mut children = self.root.as_ref();
283 let mut components = path.components(); 313 let mut components = path.components();
284 let mut component = 314 let mut component =
285 components.next().expect("expected at least one components"); 315 components.next().expect("expected at least one components");
286 loop { 316 loop {
287 let child = children.get(component)?; 317 if let Some(child) = children.get(component)? {
288 if let Some(next_component) = components.next() { 318 if let Some(next_component) = components.next() {
289 component = next_component; 319 component = next_component;
290 children = child.children(); 320 children = child.children()?;
321 } else {
322 return Ok(Some(child));
323 }
291 } else { 324 } else {
292 return Some(child); 325 return Ok(None);
293 } 326 }
294 } 327 }
295 } 328 }
296 329
297 /// Returns a mutable reference to the node at `path` if it exists 330 /// Returns a mutable reference to the node at `path` if it exists
299 /// This takes `root` instead of `&mut self` so that callers can mutate 332 /// This takes `root` instead of `&mut self` so that callers can mutate
300 /// other fields while the returned borrow is still valid 333 /// other fields while the returned borrow is still valid
301 fn get_node_mut<'tree>( 334 fn get_node_mut<'tree>(
302 root: &'tree mut ChildNodes<'on_disk>, 335 root: &'tree mut ChildNodes<'on_disk>,
303 path: &HgPath, 336 path: &HgPath,
304 ) -> Option<&'tree mut Node<'on_disk>> { 337 ) -> Result<Option<&'tree mut Node<'on_disk>>, DirstateV2ParseError> {
305 let mut children = root; 338 let mut children = root;
306 let mut components = path.components(); 339 let mut components = path.components();
307 let mut component = 340 let mut component =
308 components.next().expect("expected at least one components"); 341 components.next().expect("expected at least one components");
309 loop { 342 loop {
310 let child = children.make_mut().get_mut(component)?; 343 if let Some(child) = children.make_mut()?.get_mut(component) {
311 if let Some(next_component) = components.next() { 344 if let Some(next_component) = components.next() {
312 component = next_component; 345 component = next_component;
313 children = &mut child.children; 346 children = &mut child.children;
347 } else {
348 return Ok(Some(child));
349 }
314 } else { 350 } else {
315 return Some(child); 351 return Ok(None);
316 } 352 }
317 } 353 }
318 } 354 }
319 355
320 fn get_or_insert_node<'tree, 'path>( 356 fn get_or_insert_node<'tree, 'path>(
322 path: &'path HgPath, 358 path: &'path HgPath,
323 to_cow: impl Fn( 359 to_cow: impl Fn(
324 WithBasename<&'path HgPath>, 360 WithBasename<&'path HgPath>,
325 ) -> WithBasename<Cow<'on_disk, HgPath>>, 361 ) -> WithBasename<Cow<'on_disk, HgPath>>,
326 mut each_ancestor: impl FnMut(&mut Node), 362 mut each_ancestor: impl FnMut(&mut Node),
327 ) -> &'tree mut Node<'on_disk> { 363 ) -> Result<&'tree mut Node<'on_disk>, DirstateV2ParseError> {
328 let mut child_nodes = root; 364 let mut child_nodes = root;
329 let mut inclusive_ancestor_paths = 365 let mut inclusive_ancestor_paths =
330 WithBasename::inclusive_ancestors_of(path); 366 WithBasename::inclusive_ancestors_of(path);
331 let mut ancestor_path = inclusive_ancestor_paths 367 let mut ancestor_path = inclusive_ancestor_paths
332 .next() 368 .next()
334 loop { 370 loop {
335 // TODO: can we avoid allocating an owned key in cases where the 371 // TODO: can we avoid allocating an owned key in cases where the
336 // map already contains that key, without introducing double 372 // map already contains that key, without introducing double
337 // lookup? 373 // lookup?
338 let child_node = child_nodes 374 let child_node = child_nodes
339 .make_mut() 375 .make_mut()?
340 .entry(to_cow(ancestor_path)) 376 .entry(to_cow(ancestor_path))
341 .or_default(); 377 .or_default();
342 if let Some(next) = inclusive_ancestor_paths.next() { 378 if let Some(next) = inclusive_ancestor_paths.next() {
343 each_ancestor(child_node); 379 each_ancestor(child_node);
344 ancestor_path = next; 380 ancestor_path = next;
345 child_nodes = &mut child_node.children; 381 child_nodes = &mut child_node.children;
346 } else { 382 } else {
347 return child_node; 383 return Ok(child_node);
348 } 384 }
349 } 385 }
350 } 386 }
351 387
352 fn add_or_remove_file( 388 fn add_or_remove_file(
353 &mut self, 389 &mut self,
354 path: &HgPath, 390 path: &HgPath,
355 old_state: EntryState, 391 old_state: EntryState,
356 new_entry: DirstateEntry, 392 new_entry: DirstateEntry,
357 ) { 393 ) -> Result<(), DirstateV2ParseError> {
358 let tracked_count_increment = 394 let tracked_count_increment =
359 match (old_state.is_tracked(), new_entry.state.is_tracked()) { 395 match (old_state.is_tracked(), new_entry.state.is_tracked()) {
360 (false, true) => 1, 396 (false, true) => 1,
361 (true, false) => -1, 397 (true, false) => -1,
362 _ => 0, 398 _ => 0,
374 1 => ancestor.tracked_descendants_count += 1, 410 1 => ancestor.tracked_descendants_count += 1,
375 -1 => ancestor.tracked_descendants_count -= 1, 411 -1 => ancestor.tracked_descendants_count -= 1,
376 _ => {} 412 _ => {}
377 } 413 }
378 }, 414 },
379 ); 415 )?;
380 if node.entry.is_none() { 416 if node.entry.is_none() {
381 self.nodes_with_entry_count += 1 417 self.nodes_with_entry_count += 1
382 } 418 }
383 node.entry = Some(new_entry) 419 node.entry = Some(new_entry);
420 Ok(())
384 } 421 }
385 422
386 fn iter_nodes<'tree>( 423 fn iter_nodes<'tree>(
387 &'tree self, 424 &'tree self,
388 ) -> impl Iterator<Item = NodeRef<'tree, 'on_disk>> + 'tree { 425 ) -> impl Iterator<
426 Item = Result<NodeRef<'tree, 'on_disk>, DirstateV2ParseError>,
427 > + 'tree {
389 // Depth first tree traversal. 428 // Depth first tree traversal.
390 // 429 //
391 // If we could afford internal iteration and recursion, 430 // If we could afford internal iteration and recursion,
392 // this would look like: 431 // this would look like:
393 // 432 //
407 // call stack. Use an explicit stack instead: 446 // call stack. Use an explicit stack instead:
408 let mut stack = Vec::new(); 447 let mut stack = Vec::new();
409 let mut iter = self.root.as_ref().iter(); 448 let mut iter = self.root.as_ref().iter();
410 std::iter::from_fn(move || { 449 std::iter::from_fn(move || {
411 while let Some(child_node) = iter.next() { 450 while let Some(child_node) = iter.next() {
451 let children = match child_node.children() {
452 Ok(children) => children,
453 Err(error) => return Some(Err(error)),
454 };
412 // Pseudo-recursion 455 // Pseudo-recursion
413 let new_iter = child_node.children().iter(); 456 let new_iter = children.iter();
414 let old_iter = std::mem::replace(&mut iter, new_iter); 457 let old_iter = std::mem::replace(&mut iter, new_iter);
415 stack.push((child_node, old_iter)); 458 stack.push((child_node, old_iter));
416 } 459 }
417 // Found the end of a `children.iter()` iterator. 460 // Found the end of a `children.iter()` iterator.
418 if let Some((child_node, next_iter)) = stack.pop() { 461 if let Some((child_node, next_iter)) = stack.pop() {
419 // "Return" from pseudo-recursion by restoring state from the 462 // "Return" from pseudo-recursion by restoring state from the
420 // explicit stack 463 // explicit stack
421 iter = next_iter; 464 iter = next_iter;
422 465
423 Some(child_node) 466 Some(Ok(child_node))
424 } else { 467 } else {
425 // Reached the bottom of the stack, we’re done 468 // Reached the bottom of the stack, we’re done
426 None 469 None
427 } 470 }
428 }) 471 })
429 } 472 }
430 473
431 fn clear_known_ambiguous_mtimes(&mut self, paths: &[impl AsRef<HgPath>]) { 474 fn clear_known_ambiguous_mtimes(
475 &mut self,
476 paths: &[impl AsRef<HgPath>],
477 ) -> Result<(), DirstateV2ParseError> {
432 for path in paths { 478 for path in paths {
433 if let Some(node) = 479 if let Some(node) =
434 Self::get_node_mut(&mut self.root, path.as_ref()) 480 Self::get_node_mut(&mut self.root, path.as_ref())?
435 { 481 {
436 if let Some(entry) = node.entry.as_mut() { 482 if let Some(entry) = node.entry.as_mut() {
437 entry.clear_mtime(); 483 entry.clear_mtime();
438 } 484 }
439 } 485 }
440 } 486 }
441 } 487 Ok(())
488 }
489
490 /// Return a faillilble iterator of full paths of nodes that have an
491 /// `entry` for which the given `predicate` returns true.
492 ///
493 /// Fallibility means that each iterator item is a `Result`, which may
494 /// indicate a parse error of the on-disk dirstate-v2 format. Such errors
495 /// should only happen if Mercurial is buggy or a repository is corrupted.
496 fn filter_full_paths<'tree>(
497 &'tree self,
498 predicate: impl Fn(&DirstateEntry) -> bool + 'tree,
499 ) -> impl Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + 'tree
500 {
501 filter_map_results(self.iter_nodes(), move |node| {
502 if let Some(entry) = node.entry()? {
503 if predicate(&entry) {
504 return Ok(Some(node.full_path()?));
505 }
506 }
507 Ok(None)
508 })
509 }
510 }
511
512 /// Like `Iterator::filter_map`, but over a fallible iterator of `Result`s.
513 ///
514 /// The callback is only called for incoming `Ok` values. Errors are passed
515 /// through as-is. In order to let it use the `?` operator the callback is
516 /// expected to return a `Result` of `Option`, instead of an `Option` of
517 /// `Result`.
518 fn filter_map_results<'a, I, F, A, B, E>(
519 iter: I,
520 f: F,
521 ) -> impl Iterator<Item = Result<B, E>> + 'a
522 where
523 I: Iterator<Item = Result<A, E>> + 'a,
524 F: Fn(A) -> Result<Option<B>, E> + 'a,
525 {
526 iter.filter_map(move |result| match result {
527 Ok(node) => f(node).transpose(),
528 Err(e) => Some(Err(e)),
529 })
442 } 530 }
443 531
444 impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> { 532 impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> {
445 fn clear(&mut self) { 533 fn clear(&mut self) {
446 self.root = Default::default(); 534 self.root = Default::default();
451 fn add_file( 539 fn add_file(
452 &mut self, 540 &mut self,
453 filename: &HgPath, 541 filename: &HgPath,
454 old_state: EntryState, 542 old_state: EntryState,
455 entry: DirstateEntry, 543 entry: DirstateEntry,
456 ) -> Result<(), DirstateMapError> { 544 ) -> Result<(), DirstateError> {
457 self.add_or_remove_file(filename, old_state, entry); 545 Ok(self.add_or_remove_file(filename, old_state, entry)?)
458 Ok(())
459 } 546 }
460 547
461 fn remove_file( 548 fn remove_file(
462 &mut self, 549 &mut self,
463 filename: &HgPath, 550 filename: &HgPath,
464 old_state: EntryState, 551 old_state: EntryState,
465 size: i32, 552 size: i32,
466 ) -> Result<(), DirstateMapError> { 553 ) -> Result<(), DirstateError> {
467 let entry = DirstateEntry { 554 let entry = DirstateEntry {
468 state: EntryState::Removed, 555 state: EntryState::Removed,
469 mode: 0, 556 mode: 0,
470 size, 557 size,
471 mtime: 0, 558 mtime: 0,
472 }; 559 };
473 self.add_or_remove_file(filename, old_state, entry); 560 Ok(self.add_or_remove_file(filename, old_state, entry)?)
474 Ok(())
475 } 561 }
476 562
477 fn drop_file( 563 fn drop_file(
478 &mut self, 564 &mut self,
479 filename: &HgPath, 565 filename: &HgPath,
480 old_state: EntryState, 566 old_state: EntryState,
481 ) -> Result<bool, DirstateMapError> { 567 ) -> Result<bool, DirstateError> {
482 struct Dropped { 568 struct Dropped {
483 was_tracked: bool, 569 was_tracked: bool,
484 had_entry: bool, 570 had_entry: bool,
485 had_copy_source: bool, 571 had_copy_source: bool,
486 } 572 }
487 fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> { 573 fn recur(
574 nodes: &mut ChildNodes,
575 path: &HgPath,
576 ) -> Result<Option<Dropped>, DirstateV2ParseError> {
488 let (first_path_component, rest_of_path) = 577 let (first_path_component, rest_of_path) =
489 path.split_first_component(); 578 path.split_first_component();
490 let node = nodes.make_mut().get_mut(first_path_component)?; 579 let node = if let Some(node) =
580 nodes.make_mut()?.get_mut(first_path_component)
581 {
582 node
583 } else {
584 return Ok(None);
585 };
491 let dropped; 586 let dropped;
492 if let Some(rest) = rest_of_path { 587 if let Some(rest) = rest_of_path {
493 dropped = recur(&mut node.children, rest)?; 588 if let Some(d) = recur(&mut node.children, rest)? {
494 if dropped.was_tracked { 589 dropped = d;
495 node.tracked_descendants_count -= 1; 590 if dropped.was_tracked {
591 node.tracked_descendants_count -= 1;
592 }
593 } else {
594 return Ok(None);
496 } 595 }
497 } else { 596 } else {
498 dropped = Dropped { 597 dropped = Dropped {
499 was_tracked: node 598 was_tracked: node
500 .entry 599 .entry
508 // parent nodes, remove a node if it just became empty. 607 // parent nodes, remove a node if it just became empty.
509 if node.entry.is_none() 608 if node.entry.is_none()
510 && node.copy_source.is_none() 609 && node.copy_source.is_none()
511 && node.children.is_empty() 610 && node.children.is_empty()
512 { 611 {
513 nodes.make_mut().remove(first_path_component); 612 nodes.make_mut()?.remove(first_path_component);
514 } 613 }
515 Some(dropped) 614 Ok(Some(dropped))
516 } 615 }
517 616
518 if let Some(dropped) = recur(&mut self.root, filename) { 617 if let Some(dropped) = recur(&mut self.root, filename)? {
519 if dropped.had_entry { 618 if dropped.had_entry {
520 self.nodes_with_entry_count -= 1 619 self.nodes_with_entry_count -= 1
521 } 620 }
522 if dropped.had_copy_source { 621 if dropped.had_copy_source {
523 self.nodes_with_copy_source_count -= 1 622 self.nodes_with_copy_source_count -= 1
527 debug_assert!(!old_state.is_tracked()); 626 debug_assert!(!old_state.is_tracked());
528 Ok(false) 627 Ok(false)
529 } 628 }
530 } 629 }
531 630
532 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { 631 fn clear_ambiguous_times(
632 &mut self,
633 filenames: Vec<HgPathBuf>,
634 now: i32,
635 ) -> Result<(), DirstateV2ParseError> {
533 for filename in filenames { 636 for filename in filenames {
534 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) { 637 if let Some(node) = Self::get_node_mut(&mut self.root, &filename)?
638 {
535 if let Some(entry) = node.entry.as_mut() { 639 if let Some(entry) = node.entry.as_mut() {
536 entry.clear_ambiguous_mtime(now); 640 entry.clear_ambiguous_mtime(now);
537 } 641 }
538 } 642 }
539 } 643 }
540 } 644 Ok(())
541 645 }
542 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool { 646
543 self.get_node(key) 647 fn non_normal_entries_contains(
544 .and_then(|node| node.entry()) 648 &mut self,
545 .map_or(false, |entry| entry.is_non_normal()) 649 key: &HgPath,
650 ) -> Result<bool, DirstateV2ParseError> {
651 Ok(if let Some(node) = self.get_node(key)? {
652 node.entry()?.map_or(false, |entry| entry.is_non_normal())
653 } else {
654 false
655 })
546 } 656 }
547 657
548 fn non_normal_entries_remove(&mut self, _key: &HgPath) { 658 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
549 // Do nothing, this `DirstateMap` does not have a separate "non normal 659 // Do nothing, this `DirstateMap` does not have a separate "non normal
550 // entries" set that need to be kept up to date 660 // entries" set that need to be kept up to date
551 } 661 }
552 662
553 fn non_normal_or_other_parent_paths( 663 fn non_normal_or_other_parent_paths(
554 &mut self, 664 &mut self,
555 ) -> Box<dyn Iterator<Item = &HgPath> + '_> { 665 ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>
556 Box::new(self.iter_nodes().filter_map(|node| { 666 {
557 node.entry() 667 Box::new(self.filter_full_paths(|entry| {
558 .filter(|entry| { 668 entry.is_non_normal() || entry.is_from_other_parent()
559 entry.is_non_normal() || entry.is_from_other_parent()
560 })
561 .map(|_| node.full_path())
562 })) 669 }))
563 } 670 }
564 671
565 fn set_non_normal_other_parent_entries(&mut self, _force: bool) { 672 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
566 // Do nothing, this `DirstateMap` does not have a separate "non normal 673 // Do nothing, this `DirstateMap` does not have a separate "non normal
567 // entries" and "from other parent" sets that need to be recomputed 674 // entries" and "from other parent" sets that need to be recomputed
568 } 675 }
569 676
570 fn iter_non_normal_paths( 677 fn iter_non_normal_paths(
571 &mut self, 678 &mut self,
572 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { 679 ) -> Box<
680 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
681 > {
573 self.iter_non_normal_paths_panic() 682 self.iter_non_normal_paths_panic()
574 } 683 }
575 684
576 fn iter_non_normal_paths_panic( 685 fn iter_non_normal_paths_panic(
577 &self, 686 &self,
578 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { 687 ) -> Box<
579 Box::new(self.iter_nodes().filter_map(|node| { 688 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
580 node.entry() 689 > {
581 .filter(|entry| entry.is_non_normal()) 690 Box::new(self.filter_full_paths(|entry| entry.is_non_normal()))
582 .map(|_| node.full_path())
583 }))
584 } 691 }
585 692
586 fn iter_other_parent_paths( 693 fn iter_other_parent_paths(
587 &mut self, 694 &mut self,
588 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { 695 ) -> Box<
589 Box::new(self.iter_nodes().filter_map(|node| { 696 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
590 node.entry() 697 > {
591 .filter(|entry| entry.is_from_other_parent()) 698 Box::new(self.filter_full_paths(|entry| entry.is_from_other_parent()))
592 .map(|_| node.full_path())
593 }))
594 } 699 }
595 700
596 fn has_tracked_dir( 701 fn has_tracked_dir(
597 &mut self, 702 &mut self,
598 directory: &HgPath, 703 directory: &HgPath,
599 ) -> Result<bool, DirstateMapError> { 704 ) -> Result<bool, DirstateError> {
600 if let Some(node) = self.get_node(directory) { 705 if let Some(node) = self.get_node(directory)? {
601 // A node without a `DirstateEntry` was created to hold child 706 // A node without a `DirstateEntry` was created to hold child
602 // nodes, and is therefore a directory. 707 // nodes, and is therefore a directory.
603 Ok(!node.has_entry() && node.tracked_descendants_count() > 0) 708 Ok(!node.has_entry() && node.tracked_descendants_count() > 0)
604 } else { 709 } else {
605 Ok(false) 710 Ok(false)
606 } 711 }
607 } 712 }
608 713
609 fn has_dir( 714 fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> {
610 &mut self, 715 if let Some(node) = self.get_node(directory)? {
611 directory: &HgPath,
612 ) -> Result<bool, DirstateMapError> {
613 if let Some(node) = self.get_node(directory) {
614 // A node without a `DirstateEntry` was created to hold child 716 // A node without a `DirstateEntry` was created to hold child
615 // nodes, and is therefore a directory. 717 // nodes, and is therefore a directory.
616 Ok(!node.has_entry()) 718 Ok(!node.has_entry())
617 } else { 719 } else {
618 Ok(false) 720 Ok(false)
629 let mut ambiguous_mtimes = Vec::new(); 731 let mut ambiguous_mtimes = Vec::new();
630 // Optizimation (to be measured?): pre-compute size to avoid `Vec` 732 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
631 // reallocations 733 // reallocations
632 let mut size = parents.as_bytes().len(); 734 let mut size = parents.as_bytes().len();
633 for node in self.iter_nodes() { 735 for node in self.iter_nodes() {
634 if let Some(entry) = node.entry() { 736 let node = node?;
737 if let Some(entry) = node.entry()? {
635 size += 738 size +=
636 packed_entry_size(node.full_path(), node.copy_source()); 739 packed_entry_size(node.full_path()?, node.copy_source()?);
637 if entry.mtime_is_ambiguous(now) { 740 if entry.mtime_is_ambiguous(now) {
638 ambiguous_mtimes.push(node.full_path_cow()) 741 ambiguous_mtimes.push(node.full_path_cow()?)
639 } 742 }
640 } 743 }
641 } 744 }
642 self.clear_known_ambiguous_mtimes(&ambiguous_mtimes); 745 self.clear_known_ambiguous_mtimes(&ambiguous_mtimes)?;
643 746
644 let mut packed = Vec::with_capacity(size); 747 let mut packed = Vec::with_capacity(size);
645 packed.extend(parents.as_bytes()); 748 packed.extend(parents.as_bytes());
646 749
647 for node in self.iter_nodes() { 750 for node in self.iter_nodes() {
648 if let Some(entry) = node.entry() { 751 let node = node?;
752 if let Some(entry) = node.entry()? {
649 pack_entry( 753 pack_entry(
650 node.full_path(), 754 node.full_path()?,
651 &entry, 755 &entry,
652 node.copy_source(), 756 node.copy_source()?,
653 &mut packed, 757 &mut packed,
654 ); 758 );
655 } 759 }
656 } 760 }
657 Ok(packed) 761 Ok(packed)
665 ) -> Result<Vec<u8>, DirstateError> { 769 ) -> Result<Vec<u8>, DirstateError> {
666 // TODO: how do we want to handle this in 2038? 770 // TODO: how do we want to handle this in 2038?
667 let now: i32 = now.0.try_into().expect("time overflow"); 771 let now: i32 = now.0.try_into().expect("time overflow");
668 let mut paths = Vec::new(); 772 let mut paths = Vec::new();
669 for node in self.iter_nodes() { 773 for node in self.iter_nodes() {
670 if let Some(entry) = node.entry() { 774 let node = node?;
775 if let Some(entry) = node.entry()? {
671 if entry.mtime_is_ambiguous(now) { 776 if entry.mtime_is_ambiguous(now) {
672 paths.push(node.full_path_cow()) 777 paths.push(node.full_path_cow()?)
673 } 778 }
674 } 779 }
675 } 780 }
676 // Borrow of `self` ends here since we collect cloned paths 781 // Borrow of `self` ends here since we collect cloned paths
677 782
678 self.clear_known_ambiguous_mtimes(&paths); 783 self.clear_known_ambiguous_mtimes(&paths)?;
679 784
680 on_disk::write(self, parents) 785 on_disk::write(self, parents)
681 } 786 }
682 787
683 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { 788 fn set_all_dirs(&mut self) -> Result<(), DirstateError> {
684 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that 789 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
685 // needs to be recomputed 790 // needs to be recomputed
686 Ok(()) 791 Ok(())
687 } 792 }
688 793
689 fn set_dirs(&mut self) -> Result<(), DirstateMapError> { 794 fn set_dirs(&mut self) -> Result<(), DirstateError> {
690 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs 795 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
691 // to be recomputed 796 // to be recomputed
692 Ok(()) 797 Ok(())
693 } 798 }
694 799
706 fn copy_map_len(&self) -> usize { 811 fn copy_map_len(&self) -> usize {
707 self.nodes_with_copy_source_count as usize 812 self.nodes_with_copy_source_count as usize
708 } 813 }
709 814
710 fn copy_map_iter(&self) -> CopyMapIter<'_> { 815 fn copy_map_iter(&self) -> CopyMapIter<'_> {
711 Box::new(self.iter_nodes().filter_map(|node| { 816 Box::new(filter_map_results(self.iter_nodes(), |node| {
712 node.copy_source() 817 Ok(if let Some(source) = node.copy_source()? {
713 .map(|copy_source| (node.full_path(), copy_source)) 818 Some((node.full_path()?, source))
819 } else {
820 None
821 })
714 })) 822 }))
715 } 823 }
716 824
717 fn copy_map_contains_key(&self, key: &HgPath) -> bool { 825 fn copy_map_contains_key(
718 if let Some(node) = self.get_node(key) { 826 &self,
719 node.copy_source().is_some() 827 key: &HgPath,
828 ) -> Result<bool, DirstateV2ParseError> {
829 Ok(if let Some(node) = self.get_node(key)? {
830 node.has_copy_source()
720 } else { 831 } else {
721 false 832 false
722 } 833 })
723 } 834 }
724 835
725 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> { 836 fn copy_map_get(
726 self.get_node(key)?.copy_source() 837 &self,
727 } 838 key: &HgPath,
728 839 ) -> Result<Option<&HgPath>, DirstateV2ParseError> {
729 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> { 840 if let Some(node) = self.get_node(key)? {
841 if let Some(source) = node.copy_source()? {
842 return Ok(Some(source));
843 }
844 }
845 Ok(None)
846 }
847
848 fn copy_map_remove(
849 &mut self,
850 key: &HgPath,
851 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
730 let count = &mut self.nodes_with_copy_source_count; 852 let count = &mut self.nodes_with_copy_source_count;
731 Self::get_node_mut(&mut self.root, key).and_then(|node| { 853 Ok(Self::get_node_mut(&mut self.root, key)?.and_then(|node| {
732 if node.copy_source.is_some() { 854 if node.copy_source.is_some() {
733 *count -= 1 855 *count -= 1
734 } 856 }
735 node.copy_source.take().map(Cow::into_owned) 857 node.copy_source.take().map(Cow::into_owned)
736 }) 858 }))
737 } 859 }
738 860
739 fn copy_map_insert( 861 fn copy_map_insert(
740 &mut self, 862 &mut self,
741 key: HgPathBuf, 863 key: HgPathBuf,
742 value: HgPathBuf, 864 value: HgPathBuf,
743 ) -> Option<HgPathBuf> { 865 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
744 let node = Self::get_or_insert_node( 866 let node = Self::get_or_insert_node(
745 &mut self.root, 867 &mut self.root,
746 &key, 868 &key,
747 WithBasename::to_cow_owned, 869 WithBasename::to_cow_owned,
748 |_ancestor| {}, 870 |_ancestor| {},
749 ); 871 )?;
750 if node.copy_source.is_none() { 872 if node.copy_source.is_none() {
751 self.nodes_with_copy_source_count += 1 873 self.nodes_with_copy_source_count += 1
752 } 874 }
753 node.copy_source.replace(value.into()).map(Cow::into_owned) 875 Ok(node.copy_source.replace(value.into()).map(Cow::into_owned))
754 } 876 }
755 877
756 fn len(&self) -> usize { 878 fn len(&self) -> usize {
757 self.nodes_with_entry_count as usize 879 self.nodes_with_entry_count as usize
758 } 880 }
759 881
760 fn contains_key(&self, key: &HgPath) -> bool { 882 fn contains_key(
761 self.get(key).is_some() 883 &self,
762 } 884 key: &HgPath,
763 885 ) -> Result<bool, DirstateV2ParseError> {
764 fn get(&self, key: &HgPath) -> Option<DirstateEntry> { 886 Ok(self.get(key)?.is_some())
765 self.get_node(key)?.entry() 887 }
888
889 fn get(
890 &self,
891 key: &HgPath,
892 ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
893 Ok(if let Some(node) = self.get_node(key)? {
894 node.entry()?
895 } else {
896 None
897 })
766 } 898 }
767 899
768 fn iter(&self) -> StateMapIter<'_> { 900 fn iter(&self) -> StateMapIter<'_> {
769 Box::new(self.iter_nodes().filter_map(|node| { 901 Box::new(filter_map_results(self.iter_nodes(), |node| {
770 node.entry().map(|entry| (node.full_path(), entry)) 902 Ok(if let Some(entry) = node.entry()? {
903 Some((node.full_path()?, entry))
904 } else {
905 None
906 })
771 })) 907 }))
772 } 908 }
773 } 909 }