Patchwork D11679: rhg: simplify the type of FilelogEntry

login
register
mail settings
Submitter phabricator
Date Oct. 15, 2021, 1:21 p.m.
Message ID <differential-rev-PHID-DREV-3kgrg3ntl5qvkfazhv3w-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/50003/
State Superseded
Headers show

Comments

phabricator - Oct. 15, 2021, 1:21 p.m.
aalekseyev created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  rhg: add FilelogEntry.into_data
  
  rhg: internally, return a structured representatioon from hg cat

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

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

CHANGE DETAILS




To: aalekseyev, #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
@@ -66,6 +66,7 @@ 
             .map_err(|e| CommandError::abort(e.to_string()))?;
         files.push(hg_file);
     }
+    let files = files.iter().map(|file| file.as_ref()).collect();
     // TODO probably move this to a util function like `repo.default_rev` or
     // something when it's used somewhere else
     let rev = match rev {
@@ -74,7 +75,9 @@ 
     };
 
     let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
-    invocation.ui.write_stdout(&output.concatenated)?;
+    for (_file, contents) in output.results {
+        invocation.ui.write_stdout(&contents)?;
+    }
     if !output.missing.is_empty() {
         let short = format!("{:x}", output.node.short()).into_bytes();
         for path in &output.missing {
diff --git a/rust/hg-core/src/revlog/filelog.rs b/rust/hg-core/src/revlog/filelog.rs
--- a/rust/hg-core/src/revlog/filelog.rs
+++ b/rust/hg-core/src/revlog/filelog.rs
@@ -7,7 +7,6 @@ 
 use crate::utils::files::get_path_from_bytes;
 use crate::utils::hg_path::HgPath;
 use crate::utils::SliceExt;
-use std::borrow::Cow;
 use std::path::PathBuf;
 
 /// A specialized `Revlog` to work with file data logs.
@@ -40,7 +39,7 @@ 
         &self,
         file_rev: Revision,
     ) -> Result<FilelogEntry, RevlogError> {
-        let data = self.revlog.get_rev_data(file_rev)?;
+        let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?;
         Ok(FilelogEntry(data.into()))
     }
 }
@@ -51,22 +50,32 @@ 
     get_path_from_bytes(&encoded_bytes).into()
 }
 
-pub struct FilelogEntry<'filelog>(Cow<'filelog, [u8]>);
+pub struct FilelogEntry(Vec<u8>);
 
-impl<'filelog> FilelogEntry<'filelog> {
+impl FilelogEntry {
     /// Split into metadata and data
-    pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> {
+    /// Returns None if there is no metadata, so the entire entry is data.
+    fn split_metadata(&self) -> Result<Option<(&[u8], &[u8])>, HgError> {
         const DELIMITER: &[u8; 2] = &[b'\x01', b'\n'];
 
         if let Some(rest) = self.0.drop_prefix(DELIMITER) {
             if let Some((metadata, data)) = rest.split_2_by_slice(DELIMITER) {
-                Ok((Some(metadata), data))
+                Ok(Some((metadata, data)))
             } else {
                 Err(HgError::corrupted(
                     "Missing metadata end delimiter in filelog entry",
                 ))
             }
         } else {
+            Ok(None)
+        }
+    }
+
+    /// Split into metadata and data
+    pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> {
+        if let Some((metadata, data)) = self.split_metadata()? {
+            Ok((Some(metadata), data))
+        } else {
             Ok((None, &self.0))
         }
     }
@@ -76,4 +85,12 @@ 
         let (_metadata, data) = self.split()?;
         Ok(data)
     }
+
+    pub fn into_data(self) -> Result<Vec<u8>, HgError> {
+        if let Some((_metadata, data)) = self.split_metadata()? {
+            Ok(data.to_owned())
+        } else {
+            Ok(self.0)
+        }
+    }
 }
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
@@ -10,20 +10,19 @@ 
 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;
 
-pub struct CatOutput {
+pub struct CatOutput<'a> {
     /// Whether any file in the manifest matched the paths given as CLI
     /// arguments
     pub found_any: bool,
     /// The contents of matching files, in manifest order
-    pub concatenated: Vec<u8>,
+    pub results: Vec<(&'a HgPath, Vec<u8>)>,
     /// Which of the CLI arguments did not match any manifest file
-    pub missing: Vec<HgPathBuf>,
+    pub missing: Vec<&'a HgPath>,
     /// The node ID that the given revset was resolved to
     pub node: Node,
 }
@@ -32,7 +31,7 @@ 
 fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
     i: &mut PutBack<I>,
     needle: &'b HgPath,
-) -> Option<I::Item> {
+) -> Option<D> {
     loop {
         match i.next() {
             None => return None,
@@ -42,7 +41,7 @@ 
                     return None;
                 }
                 Ordering::Greater => continue,
-                Ordering::Equal => return Some(val),
+                Ordering::Equal => return Some(val.1),
             },
         }
     }
@@ -57,7 +56,7 @@ 
 >(
     manifest: I,
     files: J,
-) -> (Vec<(&'a HgPath, D)>, Vec<&'b HgPath>) {
+) -> (Vec<(&'b HgPath, D)>, Vec<&'b HgPath>) {
     let mut manifest = put_back(manifest);
     let mut res = vec![];
     let mut missing = vec![];
@@ -65,7 +64,7 @@ 
     for file in files {
         match find_item(&mut manifest, file) {
             None => missing.push(file),
-            Some(item) => res.push(item),
+            Some(item) => res.push((file, item)),
         }
     }
     return (res, missing);
@@ -79,38 +78,37 @@ 
 pub fn cat<'a>(
     repo: &Repo,
     revset: &str,
-    mut files: Vec<HgPathBuf>,
-) -> Result<CatOutput, RevlogError> {
+    mut files: Vec<&'a HgPath>,
+) -> Result<CatOutput<'a>, RevlogError> {
     let rev = crate::revset::resolve_single(revset, repo)?;
     let manifest = repo.manifest_for_rev(rev)?;
     let node = *repo
         .changelog()?
         .node_from_rev(rev)
         .expect("should succeed when repo.manifest did");
-    let mut bytes: Vec<u8> = vec![];
+    let mut results: Vec<(&'a HgPath, 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()),
+        files.into_iter().map(|f| f.as_ref()),
     );
 
-    for (manifest_file, node_bytes) in found {
+    for (file_path, node_bytes) in found {
         found_any = true;
-        let file_log = repo.filelog(manifest_file)?;
+        let file_log = repo.filelog(file_path)?;
         let file_node = Node::from_hex_for_repo(node_bytes)?;
-        bytes.extend(file_log.data_for_node(file_node)?.data()?);
+        results.push((
+            file_path,
+            file_log.data_for_node(file_node)?.into_data()?,
+        ));
     }
 
-    let missing: Vec<HgPathBuf> = missing
-        .iter()
-        .map(|file| (*file).to_owned())
-        .collect();
     Ok(CatOutput {
         found_any,
-        concatenated: bytes,
+        results,
         missing,
         node,
     })