Patchwork D11622: dirstate: simplify cat operation

login
register
mail settings
Submitter phabricator
Date Oct. 9, 2021, 12:17 a.m.
Message ID <differential-rev-PHID-DREV-lo4d23lrcgkhklas64wx-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49946/
State Superseded
Headers show

Comments

phabricator - Oct. 9, 2021, 12:17 a.m.
martinvonz created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11622

AFFECTED FILES
  rust/hg-core/src/operations/cat.rs
  rust/rhg/src/commands/cat.rs

CHANGE DETAILS




To: martinvonz, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs
--- a/rust/rhg/src/commands/cat.rs
+++ b/rust/rhg/src/commands/cat.rs
@@ -73,7 +73,7 @@ 
         None => format!("{:x}", repo.dirstate_parents()?.p1),
     };
 
-    let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
+    let output = cat(&repo, &rev, &files).map_err(|e| (e, rev.as_str()))?;
     invocation.ui.write_stdout(&output.concatenated)?;
     if !output.missing.is_empty() {
         let short = format!("{:x}", output.node.short()).into_bytes();
diff --git a/rust/hg-core/src/operations/cat.rs b/rust/hg-core/src/operations/cat.rs
--- a/rust/hg-core/src/operations/cat.rs
+++ b/rust/hg-core/src/operations/cat.rs
@@ -9,12 +9,9 @@ 
 use crate::revlog::revlog::RevlogError;
 use crate::revlog::Node;
 
-use crate::utils::hg_path::HgPath;
 use crate::utils::hg_path::HgPathBuf;
 
-use itertools::put_back;
-use itertools::PutBack;
-use std::cmp::Ordering;
+use std::collections::HashSet;
 
 pub struct CatOutput {
     /// Whether any file in the manifest matched the paths given as CLI
@@ -28,49 +25,6 @@ 
     pub node: Node,
 }
 
-// Find an item in an iterator over a sorted collection.
-fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
-    i: &mut PutBack<I>,
-    needle: &'b HgPath,
-) -> Option<I::Item> {
-    loop {
-        match i.next() {
-            None => return None,
-            Some(val) => match needle.as_bytes().cmp(val.0.as_bytes()) {
-                Ordering::Less => {
-                    i.put_back(val);
-                    return None;
-                }
-                Ordering::Greater => continue,
-                Ordering::Equal => return Some(val),
-            },
-        }
-    }
-}
-
-fn find_files_in_manifest<
-    'a,
-    'b,
-    D,
-    I: Iterator<Item = (&'a HgPath, D)>,
-    J: Iterator<Item = &'b HgPath>,
->(
-    manifest: I,
-    files: J,
-) -> (Vec<(&'a HgPath, D)>, Vec<&'b HgPath>) {
-    let mut manifest = put_back(manifest);
-    let mut res = vec![];
-    let mut missing = vec![];
-
-    for file in files {
-        match find_item(&mut manifest, file) {
-            None => missing.push(file),
-            Some(item) => res.push(item),
-        }
-    }
-    return (res, missing);
-}
-
 /// Output the given revision of files
 ///
 /// * `root`: Repository root
@@ -79,7 +33,7 @@ 
 pub fn cat<'a>(
     repo: &Repo,
     revset: &str,
-    mut files: Vec<HgPathBuf>,
+    files: &[HgPathBuf],
 ) -> Result<CatOutput, RevlogError> {
     let rev = crate::revset::resolve_single(revset, repo)?;
     let manifest = repo.manifest_for_rev(rev)?;
@@ -87,30 +41,24 @@ 
         .changelog()?
         .node_from_rev(rev)
         .expect("should succeed when repo.manifest did");
+
+    let mut missing: HashSet<_> = files.iter().map(|x| x.as_ref()).collect();
     let mut bytes: Vec<u8> = vec![];
-    let mut found_any = false;
-
-    files.sort_unstable();
-
-    let (found, missing) = find_files_in_manifest(
-        manifest.files_with_nodes(),
-        files.iter().map(|f| f.as_ref()),
-    );
-
-    for (manifest_file, node_bytes) in found {
-        found_any = true;
-        let file_log = repo.filelog(manifest_file)?;
-        let file_node = Node::from_hex_for_repo(node_bytes)?;
-        bytes.extend(file_log.data_for_node(file_node)?.data()?);
+    if let Some(last_path) = files.iter().max() {
+        for (path, node_bytes) in manifest.files_with_nodes() {
+            if missing.remove(&*path) {
+                let file_log = repo.filelog(path)?;
+                let file_node = Node::from_hex_for_repo(node_bytes)?;
+                bytes.extend(file_log.data_for_node(file_node)?.data()?);
+            }
+            if path >= last_path {
+                break;
+            }
+        }
     }
-
-    // make the order of the [missing] files
-    // match the order they were specified on the command line
-    let missing: Vec<_> = files
-        .iter()
-        .filter(|file| missing.contains(&file.as_ref()))
-        .map(|file| file.clone())
-        .collect();
+    let found_any = missing.len() != files.len();
+    let missing: Vec<_> =
+        missing.into_iter().map(|path| path.to_owned()).collect();
     Ok(CatOutput {
         found_any,
         concatenated: bytes,