annotate rust/hg-core/src/revlog/manifest.rs @ 52775:8497cfb0d76c

rust-manifest: add Manifestlog::inexact_data_delta_parents This is similar to manifestctx.read_delta_parents(exact=False) in manifest.py. It is useful to determine if a file was added in a changeset without delta-resolving the entire manifest. I will use it for rhg annotate.
author Mitchell Kember <mkember@janestreet.com>
date Tue, 14 Jan 2025 17:44:02 -0500
parents 94e2547e6f3d
children 7b4548a075ab
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52061
0ea323b7e3b1 rust-manifest: encode flags as `Option<NonZeroU8>`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
1 use std::num::NonZeroU8;
0ea323b7e3b1 rust-manifest: encode flags as `Option<NonZeroU8>`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
2
47991
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47985
diff changeset
3 use crate::errors::HgError;
52775
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
4 use crate::revlog::options::RevlogOpenOptions;
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
5 use crate::revlog::{Node, NodePrefix, Revlog, RevlogError};
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
6 use crate::utils::hg_path::HgPath;
52774
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52326
diff changeset
7 use crate::utils::strings::SliceExt;
51906
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51212
diff changeset
8 use crate::vfs::VfsImpl;
52775
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
9 use crate::{Graph, GraphError, Revision, UncheckedRevision, NULL_REVISION};
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
10
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
11 /// A specialized `Revlog` to work with `manifest` data format.
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
12 pub struct Manifestlog {
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
13 /// The generic `revlog` format.
51212
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50989
diff changeset
14 pub(crate) revlog: Revlog,
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
15 }
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
16
50989
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
17 impl Graph for Manifestlog {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
18 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
19 self.revlog.parents(rev)
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
20 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
21 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50988
diff changeset
22
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
23 impl Manifestlog {
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
24 /// Open the `manifest` of a repository given by its root.
51212
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50989
diff changeset
25 pub fn open(
51906
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51212
diff changeset
26 store_vfs: &VfsImpl,
51212
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50989
diff changeset
27 options: RevlogOpenOptions,
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50989
diff changeset
28 ) -> Result<Self, HgError> {
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50989
diff changeset
29 let revlog = Revlog::open(store_vfs, "00manifest.i", None, options)?;
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
30 Ok(Self { revlog })
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
31 }
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
32
47997
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
33 /// Return the `Manifest` for the given node ID.
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
34 ///
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
35 /// Note: this is a node ID in the manifestlog, typically found through
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
36 /// `ChangelogEntry::manifest_node`. It is *not* the node ID of any
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
37 /// changeset.
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
38 ///
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
39 /// See also `Repo::manifest_for_node`
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
40 pub fn data_for_node(
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
41 &self,
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
42 node: NodePrefix,
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
43 ) -> Result<Manifest, RevlogError> {
47996
6f579618ea7b rust: Rename the `Revlog::get_node_rev` method to `rev_from_node`
Simon Sapin <simon.sapin@octobus.net>
parents: 47992
diff changeset
44 let rev = self.revlog.rev_from_node(node)?;
52326
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
45 self.data(rev)
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
46 }
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
47
47997
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
48 /// Return the `Manifest` of a given revision number.
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
49 ///
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
50 /// Note: this is a revision number in the manifestlog, *not* of any
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
51 /// changeset.
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
52 ///
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
53 /// See also `Repo::manifest_for_rev`
52326
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
54 pub fn data_for_unchecked_rev(
47997
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47996
diff changeset
55 &self,
50988
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50010
diff changeset
56 rev: UncheckedRevision,
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50010
diff changeset
57 ) -> Result<Manifest, RevlogError> {
52326
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
58 let bytes = self.revlog.get_data_for_unchecked_rev(rev)?.into_owned();
50988
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50010
diff changeset
59 Ok(Manifest { bytes })
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50010
diff changeset
60 }
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50010
diff changeset
61
52326
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
62 /// Same as [`Self::data_for_unchecked_rev`] for a checked [`Revision`]
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
63 pub fn data(&self, rev: Revision) -> Result<Manifest, RevlogError> {
a3fa37bdb7ec rust: normalize `_for_unchecked_rev` naming among revlogs and the index
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52316
diff changeset
64 let bytes = self.revlog.get_data(rev)?.into_owned();
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
65 Ok(Manifest { bytes })
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
66 }
52775
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
67
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
68 /// Returns a manifest containing entries for `rev` that are not in its
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
69 /// parents. It is inexact because it might return a superset of this.
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
70 /// Equivalent to `manifestctx.read_delta_parents(exact=False)` in Python.
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
71 pub fn inexact_data_delta_parents(
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
72 &self,
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
73 rev: Revision,
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
74 ) -> Result<Manifest, RevlogError> {
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
75 let delta_parent = self.revlog.delta_parent(rev);
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
76 let parents = self.parents(rev).map_err(|err| match err {
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
77 GraphError::ParentOutOfRange(parent) => RevlogError::corrupted(
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
78 format!("rev {rev} has corrupted parent ({parent})"),
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
79 ),
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
80 })?;
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
81 if delta_parent == NULL_REVISION || !parents.contains(&delta_parent) {
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
82 return self.data(rev);
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
83 }
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
84 let mut bytes = vec![];
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
85 for chunk in self.revlog.get_data_incr(rev)?.as_patch_list()?.chunks {
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
86 bytes.extend_from_slice(chunk.data);
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
87 }
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
88 Ok(Manifest { bytes })
8497cfb0d76c rust-manifest: add Manifestlog::inexact_data_delta_parents
Mitchell Kember <mkember@janestreet.com>
parents: 52774
diff changeset
89 }
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
90 }
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
91
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
92 /// `Manifestlog` entry which knows how to interpret the `manifest` data bytes.
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
93 #[derive(Debug)]
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
94 pub struct Manifest {
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
95 /// Format for a manifest: flat sequence of variable-size entries,
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
96 /// sorted by path, each as:
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
97 ///
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
98 /// ```text
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
99 /// <path> \0 <hex_node_id> <flags> \n
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
100 /// ```
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
101 ///
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
102 /// The last entry is also terminated by a newline character.
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
103 /// Flags is one of `b""` (the empty string), `b"x"`, `b"l"`, or `b"t"`.
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
104 bytes: Vec<u8>,
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
105 }
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
106
47985
d44740725b95 rust: Rename Manifest to Manifestlog, ManifestEntry to Manifest
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
107 impl Manifest {
52072
78fc666a3e94 rust-files: check for empty manifests caused by narrow
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52061
diff changeset
108 /// Return a new empty manifest
78fc666a3e94 rust-files: check for empty manifests caused by narrow
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52061
diff changeset
109 pub fn empty() -> Self {
78fc666a3e94 rust-files: check for empty manifests caused by narrow
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52061
diff changeset
110 Self { bytes: vec![] }
78fc666a3e94 rust-files: check for empty manifests caused by narrow
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52061
diff changeset
111 }
78fc666a3e94 rust-files: check for empty manifests caused by narrow
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52061
diff changeset
112
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
113 pub fn iter(
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
114 &self,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
115 ) -> impl Iterator<Item = Result<ManifestEntry, HgError>> {
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
116 self.bytes
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
117 .split(|b| b == &b'\n')
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
118 .filter(|line| !line.is_empty())
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
119 .map(ManifestEntry::from_raw)
45546
f2de24c2b1f6 hg-core: add `files_with_nodes` to `Manifest`
Antoine Cezar <antoine.cezar@octobus.net>
parents: 45539
diff changeset
120 }
47992
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
121
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
122 /// If the given path is in this manifest, return its filelog node ID
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
123 pub fn find_by_path(
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
124 &self,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
125 path: &HgPath,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
126 ) -> Result<Option<ManifestEntry>, HgError> {
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
127 use std::cmp::Ordering::*;
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
128 let path = path.as_bytes();
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
129 // Both boundaries of this `&[u8]` slice are always at the boundary of
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
130 // an entry
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
131 let mut bytes = &*self.bytes;
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
132
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
133 // Binary search algorithm derived from `[T]::binary_search_by`
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
134 // <https://github.com/rust-lang/rust/blob/1.57.0/library/core/src/slice/mod.rs#L2221>
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
135 // except we don’t have a slice of entries. Instead we jump to the
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
136 // middle of the byte slice and look around for entry delimiters
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
137 // (newlines).
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
138 while let Some(entry_range) = Self::find_entry_near_middle_of(bytes)? {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
139 let (entry_path, rest) =
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
140 ManifestEntry::split_path(&bytes[entry_range.clone()])?;
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
141 let cmp = entry_path.cmp(path);
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
142 if cmp == Less {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
143 let after_newline = entry_range.end + 1;
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
144 bytes = &bytes[after_newline..];
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
145 } else if cmp == Greater {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
146 bytes = &bytes[..entry_range.start];
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
147 } else {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
148 return Ok(Some(ManifestEntry::from_path_and_rest(
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
149 entry_path, rest,
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
150 )));
47992
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
151 }
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
152 }
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
153 Ok(None)
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47991
diff changeset
154 }
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
155
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
156 /// If there is at least one, return the byte range of an entry *excluding*
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
157 /// the final newline.
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
158 fn find_entry_near_middle_of(
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
159 bytes: &[u8],
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
160 ) -> Result<Option<std::ops::Range<usize>>, HgError> {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
161 let len = bytes.len();
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
162 if len > 0 {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
163 let middle = bytes.len() / 2;
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
164 // Integer division rounds down, so `middle < len`.
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
165 let (before, after) = bytes.split_at(middle);
52316
f4aede0f01af rust-manifest: use `memchr` crate for all byte-finding needs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52286
diff changeset
166 let entry_start = match memchr::memrchr(b'\n', before) {
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
167 Some(i) => i + 1,
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
168 None => 0, // We choose the first entry in `bytes`
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
169 };
52316
f4aede0f01af rust-manifest: use `memchr` crate for all byte-finding needs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52286
diff changeset
170 let entry_end = match memchr::memchr(b'\n', after) {
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
171 Some(i) => {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
172 // No `+ 1` here to exclude this newline from the range
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
173 middle + i
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
174 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
175 None => {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
176 // In a well-formed manifest:
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
177 //
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
178 // * Since `len > 0`, `bytes` contains at least one entry
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
179 // * Every entry ends with a newline
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
180 // * Since `middle < len`, `after` contains at least the
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
181 // newline at the end of the last entry of `bytes`.
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
182 //
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
183 // We didn’t find a newline, so this manifest is not
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
184 // well-formed.
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
185 return Err(HgError::corrupted(
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
186 "manifest entry without \\n delimiter",
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
187 ));
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
188 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
189 };
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
190 Ok(Some(entry_start..entry_end))
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
191 } else {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
192 // len == 0
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
193 Ok(None)
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
194 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
195 }
45539
89ac95bd4993 hg-core: add `Manifest` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
196 }
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
197
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
198 /// `Manifestlog` entry which knows how to interpret the `manifest` data bytes.
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
199 #[derive(Debug)]
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
200 pub struct ManifestEntry<'manifest> {
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
201 pub path: &'manifest HgPath,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
202 pub hex_node_id: &'manifest [u8],
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
203
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
204 /// `Some` values are b'x', b'l', or 't'
52061
0ea323b7e3b1 rust-manifest: encode flags as `Option<NonZeroU8>`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
205 pub flags: Option<NonZeroU8>,
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
206 }
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
207
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
208 impl<'a> ManifestEntry<'a> {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
209 fn split_path(bytes: &[u8]) -> Result<(&[u8], &[u8]), HgError> {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
210 bytes.split_2(b'\0').ok_or_else(|| {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
211 HgError::corrupted("manifest entry without \\0 delimiter")
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
212 })
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
213 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
214
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
215 fn from_path_and_rest(path: &'a [u8], rest: &'a [u8]) -> Self {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
216 let (hex_node_id, flags) = match rest.split_last() {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
217 Some((&b'x', rest)) => (rest, Some(b'x')),
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
218 Some((&b'l', rest)) => (rest, Some(b'l')),
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
219 Some((&b't', rest)) => (rest, Some(b't')),
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
220 _ => (rest, None),
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
221 };
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
222 Self {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
223 path: HgPath::new(path),
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
224 hex_node_id,
52061
0ea323b7e3b1 rust-manifest: encode flags as `Option<NonZeroU8>`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
225 flags: flags.map(|f| f.try_into().expect("invalid flag")),
48532
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
226 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
227 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
228
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
229 fn from_raw(bytes: &'a [u8]) -> Result<Self, HgError> {
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
230 let (path, rest) = Self::split_path(bytes)?;
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
231 Ok(Self::from_path_and_rest(path, rest))
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
232 }
e293ff808a05 rhg: Use binary search in manifest lookup
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
233
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
234 pub fn node_id(&self) -> Result<Node, HgError> {
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
235 Node::from_hex_for_repo(self.hex_node_id)
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
236 }
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
237 }