comparison rust/hg-core/src/revlog/manifest.rs @ 48343:eb428010aad2

rhg: Also parse flags in the manifest parser Differential Revision: https://phab.mercurial-scm.org/D11772
author Simon Sapin <simon.sapin@octobus.net>
date Tue, 23 Nov 2021 19:39:51 +0100
parents 10c32e1b892a
children e293ff808a05
comparison
equal deleted inserted replaced
48342:10c32e1b892a 48343:eb428010aad2
2 use crate::repo::Repo; 2 use crate::repo::Repo;
3 use crate::revlog::revlog::{Revlog, RevlogError}; 3 use crate::revlog::revlog::{Revlog, RevlogError};
4 use crate::revlog::Revision; 4 use crate::revlog::Revision;
5 use crate::revlog::{Node, NodePrefix}; 5 use crate::revlog::{Node, NodePrefix};
6 use crate::utils::hg_path::HgPath; 6 use crate::utils::hg_path::HgPath;
7 use crate::utils::SliceExt;
7 8
8 /// A specialized `Revlog` to work with `manifest` data format. 9 /// A specialized `Revlog` to work with `manifest` data format.
9 pub struct Manifestlog { 10 pub struct Manifestlog {
10 /// The generic `revlog` format. 11 /// The generic `revlog` format.
11 revlog: Revlog, 12 revlog: Revlog,
53 pub struct Manifest { 54 pub struct Manifest {
54 bytes: Vec<u8>, 55 bytes: Vec<u8>,
55 } 56 }
56 57
57 impl Manifest { 58 impl Manifest {
58 /// Return an iterator over the lines of the entry. 59 pub fn iter(
59 pub fn lines(&self) -> impl Iterator<Item = &[u8]> { 60 &self,
61 ) -> impl Iterator<Item = Result<ManifestEntry, HgError>> {
60 self.bytes 62 self.bytes
61 .split(|b| b == &b'\n') 63 .split(|b| b == &b'\n')
62 .filter(|line| !line.is_empty()) 64 .filter(|line| !line.is_empty())
63 } 65 .map(|line| {
64 66 let (path, rest) = line.split_2(b'\0').ok_or_else(|| {
65 /// Return an iterator over the files of the entry.
66 pub fn files(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> {
67 self.lines().filter(|line| !line.is_empty()).map(|line| {
68 let pos =
69 line.iter().position(|x| x == &b'\0').ok_or_else(|| {
70 HgError::corrupted("manifest line should contain \\0") 67 HgError::corrupted("manifest line should contain \\0")
71 })?; 68 })?;
72 Ok(HgPath::new(&line[..pos])) 69 let path = HgPath::new(path);
73 }) 70 let (hex_node_id, flags) = match rest.split_last() {
74 } 71 Some((&b'x', rest)) => (rest, Some(b'x')),
75 72 Some((&b'l', rest)) => (rest, Some(b'l')),
76 /// Return an iterator over the files of the entry. 73 Some((&b't', rest)) => (rest, Some(b't')),
77 pub fn files_with_nodes( 74 _ => (rest, None),
78 &self, 75 };
79 ) -> impl Iterator<Item = Result<(&HgPath, &[u8]), HgError>> { 76 Ok(ManifestEntry {
80 self.lines().filter(|line| !line.is_empty()).map(|line| { 77 path,
81 let pos = 78 hex_node_id,
82 line.iter().position(|x| x == &b'\0').ok_or_else(|| { 79 flags,
83 HgError::corrupted("manifest line should contain \\0") 80 })
84 })?; 81 })
85 let hash_start = pos + 1;
86 let hash_end = hash_start + 40;
87 Ok((HgPath::new(&line[..pos]), &line[hash_start..hash_end]))
88 })
89 } 82 }
90 83
91 /// If the given path is in this manifest, return its filelog node ID 84 /// If the given path is in this manifest, return its filelog node ID
92 pub fn find_file(&self, path: &HgPath) -> Result<Option<Node>, HgError> { 85 pub fn find_file(
86 &self,
87 path: &HgPath,
88 ) -> Result<Option<ManifestEntry>, HgError> {
93 // TODO: use binary search instead of linear scan. This may involve 89 // TODO: use binary search instead of linear scan. This may involve
94 // building (and caching) an index of the byte indicex of each manifest 90 // building (and caching) an index of the byte indicex of each manifest
95 // line. 91 // line.
96 for entry in self.files_with_nodes() { 92
97 let (manifest_path, node) = entry?; 93 // TODO: use try_find when available (if still using linear scan)
98 if manifest_path == path { 94 // https://github.com/rust-lang/rust/issues/63178
99 return Ok(Some(Node::from_hex_for_repo(node)?)); 95 for entry in self.iter() {
96 let entry = entry?;
97 if entry.path == path {
98 return Ok(Some(entry));
100 } 99 }
101 } 100 }
102 Ok(None) 101 Ok(None)
103 } 102 }
104 } 103 }
104
105 /// `Manifestlog` entry which knows how to interpret the `manifest` data bytes.
106 #[derive(Debug)]
107 pub struct ManifestEntry<'manifest> {
108 pub path: &'manifest HgPath,
109 pub hex_node_id: &'manifest [u8],
110
111 /// `Some` values are b'x', b'l', or 't'
112 pub flags: Option<u8>,
113 }
114
115 impl ManifestEntry<'_> {
116 pub fn node_id(&self) -> Result<Node, HgError> {
117 Node::from_hex_for_repo(self.hex_node_id)
118 }
119 }