rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 47120 7109a38830c9
parent 47119 15395fd8ab28
child 47121 b6339a993b91
equal deleted inserted replaced
47119:15395fd8ab28 47120:7109a38830c9
    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()`
       
    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     }
       
    72 
       
    73     pub(super) fn state(&self) -> Option<EntryState> {
    64     pub(super) fn state(&self) -> Option<EntryState> {
    74         self.entry.as_ref().map(|entry| entry.state)
    65         self.entry.as_ref().map(|entry| entry.state)
    75     }
    66     }
    76 }
    67 }
    77 
    68 
   115     /// other fields while the returned borrow is still valid
   106     /// other fields while the returned borrow is still valid
   116     fn get_node_mut<'tree>(
   107     fn get_node_mut<'tree>(
   117         root: &'tree mut ChildNodes,
   108         root: &'tree mut ChildNodes,
   118         path: &HgPath,
   109         path: &HgPath,
   119     ) -> Option<&'tree mut Node> {
   110     ) -> Option<&'tree mut Node> {
   120         Self::each_and_get(root, path, |_| {})
   111         Self::get_node_mut_tracing_ancestors(root, path, |_| {})
   121     }
   112     }
   122 
   113 
   123     /// Call `each` for each ancestor node of the one at `path` (not including
   114     /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of
   124     /// that node itself), starting from nearest the root.
   115     /// the node.
   125     ///
   116     ///
   126     /// Panics (possibly after some calls to `each`) if there is no node at
   117     /// Note that `each_ancestor` may be called (with what would be ancestors)
   127     /// `path`.
   118     /// even if it turns out there is no node at `path`.
   128     fn for_each_ancestor_node<'tree>(
   119     fn get_node_mut_tracing_ancestors<'tree>(
   129         &mut self,
       
   130         path: &HgPath,
       
   131         each: impl FnMut(&mut Node),
       
   132     ) {
       
   133         let parent = path.parent();
       
   134         if !parent.is_empty() {
       
   135             Self::each_and_get(&mut self.root, parent, each)
       
   136                 .expect("missing dirstate node");
       
   137         }
       
   138     }
       
   139 
       
   140     /// Common implementation detail of `get_node_mut` and
       
   141     /// `for_each_ancestor_node`
       
   142     fn each_and_get<'tree>(
       
   143         root: &'tree mut ChildNodes,
   120         root: &'tree mut ChildNodes,
   144         path: &HgPath,
   121         path: &HgPath,
   145         mut each: impl FnMut(&mut Node),
   122         mut each_ancestor: impl FnMut(&mut Node),
   146     ) -> Option<&'tree mut Node> {
   123     ) -> Option<&'tree mut Node> {
   147         let mut children = root;
   124         let mut children = root;
   148         let mut components = path.components();
   125         let mut components = path.components();
   149         let mut component =
   126         let mut component =
   150             components.next().expect("expected at least one components");
   127             components.next().expect("expected at least one components");
   151         loop {
   128         loop {
   152             let child = children.get_mut(component)?;
   129             let child = children.get_mut(component)?;
   153             each(child);
       
   154             if let Some(next_component) = components.next() {
   130             if let Some(next_component) = components.next() {
       
   131                 each_ancestor(child);
   155                 component = next_component;
   132                 component = next_component;
   156                 children = &mut child.children;
   133                 children = &mut child.children;
   157             } else {
   134             } else {
   158                 return Some(child);
   135                 return Some(child);
   159             }
   136             }
   161     }
   138     }
   162 
   139 
   163     fn get_or_insert_node<'tree>(
   140     fn get_or_insert_node<'tree>(
   164         root: &'tree mut ChildNodes,
   141         root: &'tree mut ChildNodes,
   165         path: &HgPath,
   142         path: &HgPath,
       
   143     ) -> &'tree mut Node {
       
   144         Self::get_or_insert_node_tracing_ancestors(root, path, |_| {})
       
   145     }
       
   146 
       
   147     fn get_or_insert_node_tracing_ancestors<'tree>(
       
   148         root: &'tree mut ChildNodes,
       
   149         path: &HgPath,
       
   150         mut each_ancestor: impl FnMut(&mut Node),
   166     ) -> &'tree mut Node {
   151     ) -> &'tree mut Node {
   167         let mut child_nodes = root;
   152         let mut child_nodes = root;
   168         let mut inclusive_ancestor_paths =
   153         let mut inclusive_ancestor_paths =
   169             WithBasename::inclusive_ancestors_of(path);
   154             WithBasename::inclusive_ancestors_of(path);
   170         let mut ancestor_path = inclusive_ancestor_paths
   155         let mut ancestor_path = inclusive_ancestor_paths
   175             // map already contains that key, without introducing double
   160             // map already contains that key, without introducing double
   176             // lookup?
   161             // lookup?
   177             let child_node =
   162             let child_node =
   178                 child_nodes.entry(ancestor_path.to_owned()).or_default();
   163                 child_nodes.entry(ancestor_path.to_owned()).or_default();
   179             if let Some(next) = inclusive_ancestor_paths.next() {
   164             if let Some(next) = inclusive_ancestor_paths.next() {
       
   165                 each_ancestor(child_node);
   180                 ancestor_path = next;
   166                 ancestor_path = next;
   181                 child_nodes = &mut child_node.children;
   167                 child_nodes = &mut child_node.children;
   182             } else {
   168             } else {
   183                 return child_node;
   169                 return child_node;
   184             }
   170             }
   185         }
   171         }
   186     }
   172     }
   187 
   173 
   188     /// The meaning of `new_copy_source` is:
   174     fn add_or_remove_file(
   189     ///
       
   190     /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
       
   191     /// * `Some(None)`: set `Node::copy_source` to `None`
       
   192     /// * `None`: leave `Node::copy_source` unchanged
       
   193     fn add_file_node(
       
   194         &mut self,
   175         &mut self,
   195         path: &HgPath,
   176         path: &HgPath,
       
   177         old_state: EntryState,
   196         new_entry: DirstateEntry,
   178         new_entry: DirstateEntry,
   197         new_copy_source: Option<Option<HgPathBuf>>,
       
   198     ) {
   179     ) {
   199         let node = Self::get_or_insert_node(&mut self.root, path);
       
   200         if node.entry.is_none() {
       
   201             self.nodes_with_entry_count += 1
       
   202         }
       
   203         if let Some(source) = &new_copy_source {
       
   204             if node.copy_source.is_none() && source.is_some() {
       
   205                 self.nodes_with_copy_source_count += 1
       
   206             }
       
   207             if node.copy_source.is_some() && source.is_none() {
       
   208                 self.nodes_with_copy_source_count -= 1
       
   209             }
       
   210         }
       
   211         let tracked_count_increment =
   180         let tracked_count_increment =
   212             match (node.is_tracked_file(), new_entry.state.is_tracked()) {
   181             match (old_state.is_tracked(), new_entry.state.is_tracked()) {
   213                 (false, true) => 1,
   182                 (false, true) => 1,
   214                 (true, false) => -1,
   183                 (true, false) => -1,
   215                 _ => 0,
   184                 _ => 0,
   216             };
   185             };
   217 
   186 
   218         node.entry = Some(new_entry);
   187         let node = Self::get_or_insert_node_tracing_ancestors(
   219         if let Some(source) = new_copy_source {
   188             &mut self.root,
   220             node.copy_source = source
   189             path,
   221         }
   190             |ancestor| {
   222         // Borrow of `self.root` through `node` ends here
   191                 // We can’t use `+= increment` because the counter is unsigned,
   223 
   192                 // and we want debug builds to detect accidental underflow
   224         match tracked_count_increment {
   193                 // through zero
   225             1 => self.for_each_ancestor_node(path, |node| {
   194                 match tracked_count_increment {
   226                 node.tracked_descendants_count += 1
   195                     1 => ancestor.tracked_descendants_count += 1,
   227             }),
   196                     -1 => ancestor.tracked_descendants_count -= 1,
   228             // We can’t use `+= -1` because the counter is unsigned
   197                     _ => {}
   229             -1 => self.for_each_ancestor_node(path, |node| {
   198                 }
   230                 node.tracked_descendants_count -= 1
   199             },
   231             }),
   200         );
   232             _ => {}
   201         if node.entry.is_none() {
   233         }
   202             self.nodes_with_entry_count += 1
       
   203         }
       
   204         node.entry = Some(new_entry)
   234     }
   205     }
   235 
   206 
   236     fn iter_nodes<'a>(
   207     fn iter_nodes<'a>(
   237         &'a self,
   208         &'a self,
   238     ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
   209     ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
   327     }
   298     }
   328 
   299 
   329     fn add_file(
   300     fn add_file(
   330         &mut self,
   301         &mut self,
   331         filename: &HgPath,
   302         filename: &HgPath,
   332         _old_state: EntryState,
   303         old_state: EntryState,
   333         entry: DirstateEntry,
   304         entry: DirstateEntry,
   334     ) -> Result<(), DirstateMapError> {
   305     ) -> Result<(), DirstateMapError> {
   335         self.add_file_node(filename, entry, None);
   306         self.add_or_remove_file(filename, old_state, entry);
   336         Ok(())
   307         Ok(())
   337     }
   308     }
   338 
   309 
   339     fn remove_file(
   310     fn remove_file(
   340         &mut self,
   311         &mut self,
   341         filename: &HgPath,
   312         filename: &HgPath,
   342         _old_state: EntryState,
   313         old_state: EntryState,
   343         size: i32,
   314         size: i32,
   344     ) -> Result<(), DirstateMapError> {
   315     ) -> Result<(), DirstateMapError> {
   345         let entry = DirstateEntry {
   316         let entry = DirstateEntry {
   346             state: EntryState::Removed,
   317             state: EntryState::Removed,
   347             mode: 0,
   318             mode: 0,
   348             size,
   319             size,
   349             mtime: 0,
   320             mtime: 0,
   350         };
   321         };
   351         self.add_file_node(filename, entry, None);
   322         self.add_or_remove_file(filename, old_state, entry);
   352         Ok(())
   323         Ok(())
   353     }
   324     }
   354 
   325 
   355     fn drop_file(
   326     fn drop_file(
   356         &mut self,
   327         &mut self,
   357         filename: &HgPath,
   328         filename: &HgPath,
   358         _old_state: EntryState,
   329         old_state: EntryState,
   359     ) -> Result<bool, DirstateMapError> {
   330     ) -> Result<bool, DirstateMapError> {
   360         if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
   331         let was_tracked = old_state.is_tracked();
   361             let was_tracked = node.is_tracked_file();
   332         if let Some(node) = Self::get_node_mut_tracing_ancestors(
       
   333             &mut self.root,
       
   334             filename,
       
   335             |ancestor| {
       
   336                 if was_tracked {
       
   337                     ancestor.tracked_descendants_count -= 1
       
   338                 }
       
   339             },
       
   340         ) {
   362             let had_entry = node.entry.is_some();
   341             let had_entry = node.entry.is_some();
   363             let had_copy_source = node.copy_source.is_some();
   342             let had_copy_source = node.copy_source.is_some();
   364 
   343 
   365             // TODO: this leaves in the tree a "non-file" node. Should we
   344             // TODO: this leaves in the tree a "non-file" node. Should we
   366             // remove the node instead, together with ancestor nodes for
   345             // remove the node instead, together with ancestor nodes for
   372                 self.nodes_with_entry_count -= 1
   351                 self.nodes_with_entry_count -= 1
   373             }
   352             }
   374             if had_copy_source {
   353             if had_copy_source {
   375                 self.nodes_with_copy_source_count -= 1
   354                 self.nodes_with_copy_source_count -= 1
   376             }
   355             }
   377             if was_tracked {
       
   378                 self.for_each_ancestor_node(filename, |node| {
       
   379                     node.tracked_descendants_count -= 1
       
   380                 })
       
   381             }
       
   382             Ok(had_entry)
   356             Ok(had_entry)
   383         } else {
   357         } else {
       
   358             assert!(!was_tracked);
   384             Ok(false)
   359             Ok(false)
   385         }
   360         }
   386     }
   361     }
   387 
   362 
   388     fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
   363     fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
   511         }
   486         }
   512 
   487 
   513         let parents = parse_dirstate_entries(
   488         let parents = parse_dirstate_entries(
   514             file_contents,
   489             file_contents,
   515             |path, entry, copy_source| {
   490             |path, entry, copy_source| {
   516                 self.add_file_node(
   491                 let tracked = entry.state.is_tracked();
       
   492                 let node = Self::get_or_insert_node_tracing_ancestors(
       
   493                     &mut self.root,
   517                     path,
   494                     path,
   518                     *entry,
   495                     |ancestor| {
   519                     Some(copy_source.map(HgPath::to_owned)),
   496                         if tracked {
   520                 )
   497                             ancestor.tracked_descendants_count += 1
       
   498                         }
       
   499                     },
       
   500                 );
       
   501                 assert!(
       
   502                     node.entry.is_none(),
       
   503                     "duplicate dirstate entry in read"
       
   504                 );
       
   505                 assert!(
       
   506                     node.copy_source.is_none(),
       
   507                     "duplicate dirstate entry in read"
       
   508                 );
       
   509                 node.entry = Some(*entry);
       
   510                 node.copy_source = copy_source.map(HgPath::to_owned);
       
   511                 self.nodes_with_entry_count += 1;
       
   512                 if copy_source.is_some() {
       
   513                     self.nodes_with_copy_source_count += 1
       
   514                 }
   521             },
   515             },
   522         )?;
   516         )?;
   523 
   517 
   524         if !self.dirty_parents {
   518         if !self.dirty_parents {
   525             self.set_parents(parents);
   519             self.set_parents(parents);