rust/hg-core/src/copy_tracing.rs
changeset 45973 ed0e1339e4a8
parent 45972 8b99c473aae2
child 45974 10bb0856bb9f
--- a/rust/hg-core/src/copy_tracing.rs	Fri Oct 02 15:41:31 2020 +0200
+++ b/rust/hg-core/src/copy_tracing.rs	Mon Oct 05 01:31:32 2020 +0200
@@ -1,3 +1,4 @@
+use crate::utils::hg_path::HgPath;
 use crate::utils::hg_path::HgPathBuf;
 use crate::Revision;
 
@@ -36,6 +37,18 @@
     copied_from_p2: PathCopies,
 }
 
+/// Represent active changes that affect the copy tracing.
+enum Action<'a> {
+    /// The parent ? children edge is removing a file
+    ///
+    /// (actually, this could be the edge from the other parent, but it does
+    /// not matters)
+    Removed(&'a HgPath),
+    /// The parent ? children edge introduce copy information between (dest,
+    /// source)
+    Copied(&'a HgPath, &'a HgPath),
+}
+
 impl ChangedFiles {
     pub fn new(
         removed: HashSet<HgPathBuf>,
@@ -62,6 +75,19 @@
             copied_from_p2: PathCopies::new(),
         }
     }
+
+    /// Return an iterator over all the `Action` in this instance.
+    fn iter_actions(&self, parent: usize) -> impl Iterator<Item = Action> {
+        let copies_iter = match parent {
+            1 => self.copied_from_p1.iter(),
+            2 => self.copied_from_p2.iter(),
+            _ => unreachable!(),
+        };
+        let remove_iter = self.removed.iter();
+        let copies_iter = copies_iter.map(|(x, y)| Action::Copied(x, y));
+        let remove_iter = remove_iter.map(|x| Action::Removed(x));
+        copies_iter.chain(remove_iter)
+    }
 }
 
 /// A struct responsible for answering "is X ancestors of Y" quickly
@@ -142,46 +168,50 @@
             // Creating a new PathCopies for each `rev` ? `children` vertex.
             let (p1, p2, changes) = rev_info(*child);
 
-            let (parent, child_copies) = if rev == p1 {
-                (1, &changes.copied_from_p1)
+            let parent = if rev == p1 {
+                1
             } else {
                 assert_eq!(rev, p2);
-                (2, &changes.copied_from_p2)
+                2
             };
             let mut new_copies = copies.clone();
 
-            for (dest, source) in child_copies {
-                let entry;
-                if let Some(v) = copies.get(source) {
-                    entry = match &v.path {
-                        Some(path) => Some((*(path)).to_owned()),
-                        None => Some(source.to_owned()),
+            for action in changes.iter_actions(parent) {
+                match action {
+                    Action::Copied(dest, source) => {
+                        let entry;
+                        if let Some(v) = copies.get(source) {
+                            entry = match &v.path {
+                                Some(path) => Some((*(path)).to_owned()),
+                                None => Some(source.to_owned()),
+                            }
+                        } else {
+                            entry = Some(source.to_owned());
+                        }
+                        // Each new entry is introduced by the children, we
+                        // record this information as we will need it to take
+                        // the right decision when merging conflicting copy
+                        // information. See merge_copies_dict for details.
+                        let ttpc = TimeStampedPathCopy {
+                            rev: *child,
+                            path: entry,
+                        };
+                        new_copies.insert(dest.to_owned(), ttpc);
                     }
-                } else {
-                    entry = Some(source.to_owned());
-                }
-                // Each new entry is introduced by the children, we record this
-                // information as we will need it to take the right decision
-                // when merging conflicting copy information. See
-                // merge_copies_dict for details.
-                let ttpc = TimeStampedPathCopy {
-                    rev: *child,
-                    path: entry,
-                };
-                new_copies.insert(dest.to_owned(), ttpc);
-            }
-
-            // We must drop copy information for removed file.
-            //
-            // We need to explicitly record them as dropped to propagate this
-            // information when merging two TimeStampedPathCopies object.
-            for f in changes.removed.iter() {
-                if new_copies.contains_key(f.as_ref()) {
-                    let ttpc = TimeStampedPathCopy {
-                        rev: *child,
-                        path: None,
-                    };
-                    new_copies.insert(f.to_owned(), ttpc);
+                    Action::Removed(f) => {
+                        // We must drop copy information for removed file.
+                        //
+                        // We need to explicitly record them as dropped to
+                        // propagate this information when merging two
+                        // TimeStampedPathCopies object.
+                        if new_copies.contains_key(f.as_ref()) {
+                            let ttpc = TimeStampedPathCopy {
+                                rev: *child,
+                                path: None,
+                            };
+                            new_copies.insert(f.to_owned(), ttpc);
+                        }
+                    }
                 }
             }