Mercurial > public > mercurial-scm > hg
diff rust/hg-core/src/operations/dirstate_status.rs @ 45610:496537c9c1b4
rust: start plugging the dirstate tree behind a feature gate
The previous patch added the `dirstate-tree` feature gate to enable the two
dirstate implementations to co-habit while the tree-based one gets better.
This patch copies over the code that differs, be it because the algorithm
changed or because the borrowing rules are different.
Indeed, `DirstateTree` is not observationally equivalent to the std `HashMap` in
the APIs we use: it does not have the `Entry` API (yet?) and its iterator
returns owned values instead of references. This last point is because the
implementation needs to be changed to a more clever and efficient solution.
Differential Revision: https://phab.mercurial-scm.org/D9133
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Wed, 30 Sep 2020 18:10:29 +0200 |
parents | 452ece5654c5 |
children | 5c736ba5dc27 |
line wrap: on
line diff
--- a/rust/hg-core/src/operations/dirstate_status.rs Wed Sep 30 18:10:53 2020 +0200 +++ b/rust/hg-core/src/operations/dirstate_status.rs Wed Sep 30 18:10:29 2020 +0200 @@ -14,6 +14,66 @@ /// files. pub type LookupAndStatus<'a> = (Vec<HgPathCow<'a>>, DirstateStatus<'a>); +#[cfg(feature = "dirstate-tree")] +impl<'a, M: Matcher + Sync> Status<'a, M> { + pub(crate) fn run(&self) -> Result<LookupAndStatus<'a>, StatusError> { + let (traversed_sender, traversed_receiver) = + crossbeam::channel::unbounded(); + + // Step 1: check the files explicitly mentioned by the user + let (work, mut results) = self.walk_explicit(traversed_sender.clone()); + + // Step 2: Check files in the dirstate + if !self.matcher.is_exact() { + self.extend_from_dmap(&mut results); + } + // Step 3: Check the working directory if listing unknowns + if !work.is_empty() { + // Hashmaps are quite a bit slower to build than vecs, so only + // build it if needed. + let mut old_results = None; + + // Step 2: recursively check the working directory for changes if + // needed + for (dir, dispatch) in work { + match dispatch { + Dispatch::Directory { was_file } => { + if was_file { + results.push((dir.to_owned(), Dispatch::Removed)); + } + if self.options.list_ignored + || self.options.list_unknown + && !self.dir_ignore(&dir) + { + if old_results.is_none() { + old_results = + Some(results.iter().cloned().collect()); + } + self.traverse( + &dir, + old_results + .as_ref() + .expect("old results should exist"), + &mut results, + traversed_sender.clone(), + )?; + } + } + _ => { + unreachable!("There can only be directories in `work`") + } + } + } + } + + drop(traversed_sender); + let traversed = traversed_receiver.into_iter().collect(); + + Ok(build_response(results, traversed)) + } +} + +#[cfg(not(feature = "dirstate-tree"))] impl<'a, M: Matcher + Sync> Status<'a, M> { pub(crate) fn run(&self) -> Result<LookupAndStatus<'a>, StatusError> { let (traversed_sender, traversed_receiver) =