##// END OF EJS Templates
rust: use the new `UncheckedRevision` everywhere applicable...
Raphaël Gomès -
r51870:1928b770 default
parent child Browse files
Show More
@@ -84,10 +84,10 b" pub fn cat<'a>("
84 mut files: Vec<&'a HgPath>,
84 mut files: Vec<&'a HgPath>,
85 ) -> Result<CatOutput<'a>, RevlogError> {
85 ) -> Result<CatOutput<'a>, RevlogError> {
86 let rev = crate::revset::resolve_single(revset, repo)?;
86 let rev = crate::revset::resolve_single(revset, repo)?;
87 let manifest = repo.manifest_for_rev(rev)?;
87 let manifest = repo.manifest_for_rev(rev.into())?;
88 let node = *repo
88 let node = *repo
89 .changelog()?
89 .changelog()?
90 .node_from_rev(rev)
90 .node_from_rev(rev.into())
91 .expect("should succeed when repo.manifest did");
91 .expect("should succeed when repo.manifest did");
92 let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![];
92 let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![];
93 let mut found_any = false;
93 let mut found_any = false;
@@ -33,6 +33,6 b' pub fn debug_data('
33 Revlog::open(&repo.store_vfs(), index_file, None, use_nodemap)?;
33 Revlog::open(&repo.store_vfs(), index_file, None, use_nodemap)?;
34 let rev =
34 let rev =
35 crate::revset::resolve_rev_number_or_hex_prefix(revset, &revlog)?;
35 crate::revset::resolve_rev_number_or_hex_prefix(revset, &revlog)?;
36 let data = revlog.get_rev_data(rev)?;
36 let data = revlog.get_rev_data_for_checked_rev(rev)?;
37 Ok(data.into_owned())
37 Ok(data.into_owned())
38 }
38 }
@@ -21,7 +21,7 b' pub fn list_rev_tracked_files('
21 ) -> Result<FilesForRev, RevlogError> {
21 ) -> Result<FilesForRev, RevlogError> {
22 let rev = crate::revset::resolve_single(revset, repo)?;
22 let rev = crate::revset::resolve_single(revset, repo)?;
23 Ok(FilesForRev {
23 Ok(FilesForRev {
24 manifest: repo.manifest_for_rev(rev)?,
24 manifest: repo.manifest_for_rev(rev.into())?,
25 narrow_matcher,
25 narrow_matcher,
26 })
26 })
27 }
27 }
@@ -15,8 +15,8 b' use crate::utils::files::get_path_from_b'
15 use crate::utils::hg_path::HgPath;
15 use crate::utils::hg_path::HgPath;
16 use crate::utils::SliceExt;
16 use crate::utils::SliceExt;
17 use crate::vfs::{is_dir, is_file, Vfs};
17 use crate::vfs::{is_dir, is_file, Vfs};
18 use crate::{requirements, NodePrefix};
18 use crate::DirstateError;
19 use crate::{DirstateError, Revision};
19 use crate::{requirements, NodePrefix, UncheckedRevision};
20 use std::cell::{Ref, RefCell, RefMut};
20 use std::cell::{Ref, RefCell, RefMut};
21 use std::collections::HashSet;
21 use std::collections::HashSet;
22 use std::io::Seek;
22 use std::io::Seek;
@@ -562,7 +562,7 b' impl Repo {'
562 /// Returns the manifest of the *changeset* with the given revision number
562 /// Returns the manifest of the *changeset* with the given revision number
563 pub fn manifest_for_rev(
563 pub fn manifest_for_rev(
564 &self,
564 &self,
565 revision: Revision,
565 revision: UncheckedRevision,
566 ) -> Result<Manifest, RevlogError> {
566 ) -> Result<Manifest, RevlogError> {
567 self.manifestlog()?.data_for_node(
567 self.manifestlog()?.data_for_node(
568 self.changelog()?
568 self.changelog()?
@@ -4,6 +4,7 b' use crate::revlog::{Node, NodePrefix};'
4 use crate::revlog::{Revlog, RevlogEntry, RevlogError};
4 use crate::revlog::{Revlog, RevlogEntry, RevlogError};
5 use crate::utils::hg_path::HgPath;
5 use crate::utils::hg_path::HgPath;
6 use crate::vfs::Vfs;
6 use crate::vfs::Vfs;
7 use crate::UncheckedRevision;
7 use itertools::Itertools;
8 use itertools::Itertools;
8 use std::ascii::escape_default;
9 use std::ascii::escape_default;
9 use std::borrow::Cow;
10 use std::borrow::Cow;
@@ -29,15 +30,24 b' impl Changelog {'
29 node: NodePrefix,
30 node: NodePrefix,
30 ) -> Result<ChangelogRevisionData, RevlogError> {
31 ) -> Result<ChangelogRevisionData, RevlogError> {
31 let rev = self.revlog.rev_from_node(node)?;
32 let rev = self.revlog.rev_from_node(node)?;
32 self.data_for_rev(rev)
33 self.entry_for_checked_rev(rev)?.data()
33 }
34 }
34
35
35 /// Return the [`ChangelogEntry`] for the given revision number.
36 /// Return the [`ChangelogEntry`] for the given revision number.
36 pub fn entry_for_rev(
37 pub fn entry_for_rev(
37 &self,
38 &self,
39 rev: UncheckedRevision,
40 ) -> Result<ChangelogEntry, RevlogError> {
41 let revlog_entry = self.revlog.get_entry(rev)?;
42 Ok(ChangelogEntry { revlog_entry })
43 }
44
45 /// Same as [`Self::entry_for_rev`] for checked revisions.
46 fn entry_for_checked_rev(
47 &self,
38 rev: Revision,
48 rev: Revision,
39 ) -> Result<ChangelogEntry, RevlogError> {
49 ) -> Result<ChangelogEntry, RevlogError> {
40 let revlog_entry = self.revlog.get_entry(rev)?;
50 let revlog_entry = self.revlog.get_entry_for_checked_rev(rev)?;
41 Ok(ChangelogEntry { revlog_entry })
51 Ok(ChangelogEntry { revlog_entry })
42 }
52 }
43
53
@@ -49,12 +59,12 b' impl Changelog {'
49 /// [entry_for_rev](`Self::entry_for_rev`) and doing everything from there.
59 /// [entry_for_rev](`Self::entry_for_rev`) and doing everything from there.
50 pub fn data_for_rev(
60 pub fn data_for_rev(
51 &self,
61 &self,
52 rev: Revision,
62 rev: UncheckedRevision,
53 ) -> Result<ChangelogRevisionData, RevlogError> {
63 ) -> Result<ChangelogRevisionData, RevlogError> {
54 self.entry_for_rev(rev)?.data()
64 self.entry_for_rev(rev)?.data()
55 }
65 }
56
66
57 pub fn node_from_rev(&self, rev: Revision) -> Option<&Node> {
67 pub fn node_from_rev(&self, rev: UncheckedRevision) -> Option<&Node> {
58 self.revlog.node_from_rev(rev)
68 self.revlog.node_from_rev(rev)
59 }
69 }
60
70
@@ -330,12 +340,12 b' message",'
330
340
331 let changelog = Changelog { revlog };
341 let changelog = Changelog { revlog };
332 assert_eq!(
342 assert_eq!(
333 changelog.data_for_rev(NULL_REVISION)?,
343 changelog.data_for_rev(NULL_REVISION.into())?,
334 ChangelogRevisionData::null()
344 ChangelogRevisionData::null()
335 );
345 );
336 // same with the intermediate entry object
346 // same with the intermediate entry object
337 assert_eq!(
347 assert_eq!(
338 changelog.entry_for_rev(NULL_REVISION)?.data()?,
348 changelog.entry_for_rev(NULL_REVISION.into())?.data()?,
339 ChangelogRevisionData::null()
349 ChangelogRevisionData::null()
340 );
350 );
341 Ok(())
351 Ok(())
@@ -1,4 +1,5 b''
1 use crate::errors::HgError;
1 use crate::errors::HgError;
2 use crate::exit_codes;
2 use crate::repo::Repo;
3 use crate::repo::Repo;
3 use crate::revlog::path_encode::path_encode;
4 use crate::revlog::path_encode::path_encode;
4 use crate::revlog::NodePrefix;
5 use crate::revlog::NodePrefix;
@@ -8,6 +9,7 b' use crate::revlog::{Revlog, RevlogError}'
8 use crate::utils::files::get_path_from_bytes;
9 use crate::utils::files::get_path_from_bytes;
9 use crate::utils::hg_path::HgPath;
10 use crate::utils::hg_path::HgPath;
10 use crate::utils::SliceExt;
11 use crate::utils::SliceExt;
12 use crate::UncheckedRevision;
11 use std::path::PathBuf;
13 use std::path::PathBuf;
12
14
13 /// A specialized `Revlog` to work with file data logs.
15 /// A specialized `Revlog` to work with file data logs.
@@ -39,14 +41,14 b' impl Filelog {'
39 file_node: impl Into<NodePrefix>,
41 file_node: impl Into<NodePrefix>,
40 ) -> Result<FilelogRevisionData, RevlogError> {
42 ) -> Result<FilelogRevisionData, RevlogError> {
41 let file_rev = self.revlog.rev_from_node(file_node.into())?;
43 let file_rev = self.revlog.rev_from_node(file_node.into())?;
42 self.data_for_rev(file_rev)
44 self.data_for_rev(file_rev.into())
43 }
45 }
44
46
45 /// The given revision is that of the file as found in a filelog, not of a
47 /// The given revision is that of the file as found in a filelog, not of a
46 /// changeset.
48 /// changeset.
47 pub fn data_for_rev(
49 pub fn data_for_rev(
48 &self,
50 &self,
49 file_rev: Revision,
51 file_rev: UncheckedRevision,
50 ) -> Result<FilelogRevisionData, RevlogError> {
52 ) -> Result<FilelogRevisionData, RevlogError> {
51 let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?.into_owned();
53 let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?.into_owned();
52 Ok(FilelogRevisionData(data))
54 Ok(FilelogRevisionData(data))
@@ -59,16 +61,25 b' impl Filelog {'
59 file_node: impl Into<NodePrefix>,
61 file_node: impl Into<NodePrefix>,
60 ) -> Result<FilelogEntry, RevlogError> {
62 ) -> Result<FilelogEntry, RevlogError> {
61 let file_rev = self.revlog.rev_from_node(file_node.into())?;
63 let file_rev = self.revlog.rev_from_node(file_node.into())?;
62 self.entry_for_rev(file_rev)
64 self.entry_for_checked_rev(file_rev)
63 }
65 }
64
66
65 /// The given revision is that of the file as found in a filelog, not of a
67 /// The given revision is that of the file as found in a filelog, not of a
66 /// changeset.
68 /// changeset.
67 pub fn entry_for_rev(
69 pub fn entry_for_rev(
68 &self,
70 &self,
71 file_rev: UncheckedRevision,
72 ) -> Result<FilelogEntry, RevlogError> {
73 Ok(FilelogEntry(self.revlog.get_entry(file_rev)?))
74 }
75
76 fn entry_for_checked_rev(
77 &self,
69 file_rev: Revision,
78 file_rev: Revision,
70 ) -> Result<FilelogEntry, RevlogError> {
79 ) -> Result<FilelogEntry, RevlogError> {
71 Ok(FilelogEntry(self.revlog.get_entry(file_rev)?))
80 Ok(FilelogEntry(
81 self.revlog.get_entry_for_checked_rev(file_rev)?,
82 ))
72 }
83 }
73 }
84 }
74
85
@@ -165,7 +176,19 b" impl FilelogEntry<'_> {"
165 }
176 }
166
177
167 pub fn data(&self) -> Result<FilelogRevisionData, HgError> {
178 pub fn data(&self) -> Result<FilelogRevisionData, HgError> {
168 Ok(FilelogRevisionData(self.0.data()?.into_owned()))
179 let data = self.0.data();
180 match data {
181 Ok(data) => Ok(FilelogRevisionData(data.into_owned())),
182 // Errors other than `HgError` should not happen at this point
183 Err(e) => match e {
184 RevlogError::Other(hg_error) => Err(hg_error),
185 revlog_error => Err(HgError::abort(
186 revlog_error.to_string(),
187 exit_codes::ABORT,
188 None,
189 )),
190 },
191 }
169 }
192 }
170 }
193 }
171
194
@@ -1,3 +1,4 b''
1 use std::fmt::Debug;
1 use std::ops::Deref;
2 use std::ops::Deref;
2
3
3 use byteorder::{BigEndian, ByteOrder};
4 use byteorder::{BigEndian, ByteOrder};
@@ -5,6 +6,7 b' use byteorder::{BigEndian, ByteOrder};'
5 use crate::errors::HgError;
6 use crate::errors::HgError;
6 use crate::revlog::node::Node;
7 use crate::revlog::node::Node;
7 use crate::revlog::{Revision, NULL_REVISION};
8 use crate::revlog::{Revision, NULL_REVISION};
9 use crate::UncheckedRevision;
8
10
9 pub const INDEX_ENTRY_SIZE: usize = 64;
11 pub const INDEX_ENTRY_SIZE: usize = 64;
10
12
@@ -86,6 +88,15 b' pub struct Index {'
86 uses_generaldelta: bool,
88 uses_generaldelta: bool,
87 }
89 }
88
90
91 impl Debug for Index {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.debug_struct("Index")
94 .field("offsets", &self.offsets)
95 .field("uses_generaldelta", &self.uses_generaldelta)
96 .finish()
97 }
98 }
99
89 impl Index {
100 impl Index {
90 /// Create an index from bytes.
101 /// Create an index from bytes.
91 /// Calculate the start of each entry when is_inline is true.
102 /// Calculate the start of each entry when is_inline is true.
@@ -175,36 +186,32 b' impl Index {'
175 if rev == NULL_REVISION {
186 if rev == NULL_REVISION {
176 return None;
187 return None;
177 }
188 }
178 if let Some(offsets) = &self.offsets {
189 Some(if let Some(offsets) = &self.offsets {
179 self.get_entry_inline(rev, offsets)
190 self.get_entry_inline(rev, offsets)
180 } else {
191 } else {
181 self.get_entry_separated(rev)
192 self.get_entry_separated(rev)
182 }
193 })
183 }
194 }
184
195
185 fn get_entry_inline(
196 fn get_entry_inline(
186 &self,
197 &self,
187 rev: Revision,
198 rev: Revision,
188 offsets: &[usize],
199 offsets: &[usize],
189 ) -> Option<IndexEntry> {
200 ) -> IndexEntry {
190 let start = *offsets.get(rev as usize)?;
201 let start = offsets[rev as usize];
191 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
202 let end = start + INDEX_ENTRY_SIZE;
192 let bytes = &self.bytes[start..end];
203 let bytes = &self.bytes[start..end];
193
204
194 // See IndexEntry for an explanation of this override.
205 // See IndexEntry for an explanation of this override.
195 let offset_override = Some(end);
206 let offset_override = Some(end);
196
207
197 Some(IndexEntry {
208 IndexEntry {
198 bytes,
209 bytes,
199 offset_override,
210 offset_override,
200 })
211 }
201 }
212 }
202
213
203 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
214 fn get_entry_separated(&self, rev: Revision) -> IndexEntry {
204 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
205 if rev as usize >= max_rev {
206 return None;
207 }
208 let start = rev as usize * INDEX_ENTRY_SIZE;
215 let start = rev as usize * INDEX_ENTRY_SIZE;
209 let end = start + INDEX_ENTRY_SIZE;
216 let end = start + INDEX_ENTRY_SIZE;
210 let bytes = &self.bytes[start..end];
217 let bytes = &self.bytes[start..end];
@@ -213,10 +220,10 b' impl Index {'
213 // for the index's metadata (saving space because it is always 0)
220 // for the index's metadata (saving space because it is always 0)
214 let offset_override = if rev == 0 { Some(0) } else { None };
221 let offset_override = if rev == 0 { Some(0) } else { None };
215
222
216 Some(IndexEntry {
223 IndexEntry {
217 bytes,
224 bytes,
218 offset_override,
225 offset_override,
219 })
226 }
220 }
227 }
221 }
228 }
222
229
@@ -273,23 +280,23 b" impl<'a> IndexEntry<'a> {"
273 }
280 }
274
281
275 /// Return the revision upon which the data has been derived.
282 /// Return the revision upon which the data has been derived.
276 pub fn base_revision_or_base_of_delta_chain(&self) -> Revision {
283 pub fn base_revision_or_base_of_delta_chain(&self) -> UncheckedRevision {
277 // TODO Maybe return an Option when base_revision == rev?
284 // TODO Maybe return an Option when base_revision == rev?
278 // Requires to add rev to IndexEntry
285 // Requires to add rev to IndexEntry
279
286
280 BigEndian::read_i32(&self.bytes[16..])
287 BigEndian::read_i32(&self.bytes[16..]).into()
281 }
288 }
282
289
283 pub fn link_revision(&self) -> Revision {
290 pub fn link_revision(&self) -> UncheckedRevision {
284 BigEndian::read_i32(&self.bytes[20..])
291 BigEndian::read_i32(&self.bytes[20..]).into()
285 }
292 }
286
293
287 pub fn p1(&self) -> Revision {
294 pub fn p1(&self) -> UncheckedRevision {
288 BigEndian::read_i32(&self.bytes[24..])
295 BigEndian::read_i32(&self.bytes[24..]).into()
289 }
296 }
290
297
291 pub fn p2(&self) -> Revision {
298 pub fn p2(&self) -> UncheckedRevision {
292 BigEndian::read_i32(&self.bytes[28..])
299 BigEndian::read_i32(&self.bytes[28..]).into()
293 }
300 }
294
301
295 /// Return the hash of revision's full text.
302 /// Return the hash of revision's full text.
@@ -547,7 +554,7 b' mod tests {'
547 offset_override: None,
554 offset_override: None,
548 };
555 };
549
556
550 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1)
557 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1.into())
551 }
558 }
552
559
553 #[test]
560 #[test]
@@ -559,7 +566,7 b' mod tests {'
559 offset_override: None,
566 offset_override: None,
560 };
567 };
561
568
562 assert_eq!(entry.link_revision(), 123);
569 assert_eq!(entry.link_revision(), 123.into());
563 }
570 }
564
571
565 #[test]
572 #[test]
@@ -571,7 +578,7 b' mod tests {'
571 offset_override: None,
578 offset_override: None,
572 };
579 };
573
580
574 assert_eq!(entry.p1(), 123);
581 assert_eq!(entry.p1(), 123.into());
575 }
582 }
576
583
577 #[test]
584 #[test]
@@ -583,7 +590,7 b' mod tests {'
583 offset_override: None,
590 offset_override: None,
584 };
591 };
585
592
586 assert_eq!(entry.p2(), 123);
593 assert_eq!(entry.p2(), 123.into());
587 }
594 }
588
595
589 #[test]
596 #[test]
@@ -1,10 +1,10 b''
1 use crate::errors::HgError;
1 use crate::errors::HgError;
2 use crate::revlog::Revision;
3 use crate::revlog::{Node, NodePrefix};
2 use crate::revlog::{Node, NodePrefix};
4 use crate::revlog::{Revlog, RevlogError};
3 use crate::revlog::{Revlog, RevlogError};
5 use crate::utils::hg_path::HgPath;
4 use crate::utils::hg_path::HgPath;
6 use crate::utils::SliceExt;
5 use crate::utils::SliceExt;
7 use crate::vfs::Vfs;
6 use crate::vfs::Vfs;
7 use crate::{Revision, UncheckedRevision};
8
8
9 /// A specialized `Revlog` to work with `manifest` data format.
9 /// A specialized `Revlog` to work with `manifest` data format.
10 pub struct Manifestlog {
10 pub struct Manifestlog {
@@ -32,7 +32,7 b' impl Manifestlog {'
32 node: NodePrefix,
32 node: NodePrefix,
33 ) -> Result<Manifest, RevlogError> {
33 ) -> Result<Manifest, RevlogError> {
34 let rev = self.revlog.rev_from_node(node)?;
34 let rev = self.revlog.rev_from_node(node)?;
35 self.data_for_rev(rev)
35 self.data_for_checked_rev(rev)
36 }
36 }
37
37
38 /// Return the `Manifest` of a given revision number.
38 /// Return the `Manifest` of a given revision number.
@@ -43,9 +43,18 b' impl Manifestlog {'
43 /// See also `Repo::manifest_for_rev`
43 /// See also `Repo::manifest_for_rev`
44 pub fn data_for_rev(
44 pub fn data_for_rev(
45 &self,
45 &self,
46 rev: UncheckedRevision,
47 ) -> Result<Manifest, RevlogError> {
48 let bytes = self.revlog.get_rev_data(rev)?.into_owned();
49 Ok(Manifest { bytes })
50 }
51
52 pub fn data_for_checked_rev(
53 &self,
46 rev: Revision,
54 rev: Revision,
47 ) -> Result<Manifest, RevlogError> {
55 ) -> Result<Manifest, RevlogError> {
48 let bytes = self.revlog.get_rev_data(rev)?.into_owned();
56 let bytes =
57 self.revlog.get_rev_data_for_checked_rev(rev)?.into_owned();
49 Ok(Manifest { bytes })
58 Ok(Manifest { bytes })
50 }
59 }
51 }
60 }
@@ -47,7 +47,24 b' pub type Revision = i32;'
47 ///
47 ///
48 /// As noted in revlog.c, revision numbers are actually encoded in
48 /// As noted in revlog.c, revision numbers are actually encoded in
49 /// 4 bytes, and are liberally converted to ints, whence the i32
49 /// 4 bytes, and are liberally converted to ints, whence the i32
50 pub type UncheckedRevision = i32;
50 #[derive(
51 Debug,
52 derive_more::Display,
53 Clone,
54 Copy,
55 Hash,
56 PartialEq,
57 Eq,
58 PartialOrd,
59 Ord,
60 )]
61 pub struct UncheckedRevision(i32);
62
63 impl From<Revision> for UncheckedRevision {
64 fn from(value: Revision) -> Self {
65 Self(value)
66 }
67 }
51
68
52 /// Marker expressing the absence of a parent
69 /// Marker expressing the absence of a parent
53 ///
70 ///
@@ -60,7 +77,8 b' pub const NULL_REVISION: Revision = -1;'
60 /// This is also equal to `i32::max_value()`, but it's better to spell
77 /// This is also equal to `i32::max_value()`, but it's better to spell
61 /// it out explicitely, same as in `mercurial.node`
78 /// it out explicitely, same as in `mercurial.node`
62 #[allow(clippy::unreadable_literal)]
79 #[allow(clippy::unreadable_literal)]
63 pub const WORKING_DIRECTORY_REVISION: Revision = 0x7fffffff;
80 pub const WORKING_DIRECTORY_REVISION: UncheckedRevision =
81 UncheckedRevision(0x7fffffff);
64
82
65 pub const WORKING_DIRECTORY_HEX: &str =
83 pub const WORKING_DIRECTORY_HEX: &str =
66 "ffffffffffffffffffffffffffffffffffffffff";
84 "ffffffffffffffffffffffffffffffffffffffff";
@@ -90,14 +108,14 b' pub trait RevlogIndex {'
90 self.len() == 0
108 self.len() == 0
91 }
109 }
92
110
93 /// Return a reference to the Node or `None` if rev is out of bounds
111 /// Return a reference to the Node or `None` for `NULL_REVISION`
94 ///
95 /// `NULL_REVISION` is not considered to be out of bounds.
96 fn node(&self, rev: Revision) -> Option<&Node>;
112 fn node(&self, rev: Revision) -> Option<&Node>;
97
113
98 /// Return a [`Revision`] if `rev` is a valid revision number for this
114 /// Return a [`Revision`] if `rev` is a valid revision number for this
99 /// index
115 /// index
100 fn check_revision(&self, rev: UncheckedRevision) -> Option<Revision> {
116 fn check_revision(&self, rev: UncheckedRevision) -> Option<Revision> {
117 let rev = rev.0;
118
101 if rev == NULL_REVISION || (rev >= 0 && (rev as usize) < self.len()) {
119 if rev == NULL_REVISION || (rev >= 0 && (rev as usize) < self.len()) {
102 Some(rev)
120 Some(rev)
103 } else {
121 } else {
@@ -120,7 +138,7 b' const REVIDX_KNOWN_FLAGS: u16 = REVISION'
120
138
121 const NULL_REVLOG_ENTRY_FLAGS: u16 = 0;
139 const NULL_REVLOG_ENTRY_FLAGS: u16 = 0;
122
140
123 #[derive(Debug, derive_more::From)]
141 #[derive(Debug, derive_more::From, derive_more::Display)]
124 pub enum RevlogError {
142 pub enum RevlogError {
125 InvalidRevision,
143 InvalidRevision,
126 /// Working directory is not supported
144 /// Working directory is not supported
@@ -231,10 +249,11 b' impl Revlog {'
231
249
232 /// Returns the node ID for the given revision number, if it exists in this
250 /// Returns the node ID for the given revision number, if it exists in this
233 /// revlog
251 /// revlog
234 pub fn node_from_rev(&self, rev: Revision) -> Option<&Node> {
252 pub fn node_from_rev(&self, rev: UncheckedRevision) -> Option<&Node> {
235 if rev == NULL_REVISION {
253 if rev == NULL_REVISION.into() {
236 return Some(&NULL_NODE);
254 return Some(&NULL_NODE);
237 }
255 }
256 let rev = self.index.check_revision(rev)?;
238 Some(self.index.get_entry(rev)?.hash())
257 Some(self.index.get_entry(rev)?.hash())
239 }
258 }
240
259
@@ -296,8 +315,8 b' impl Revlog {'
296 }
315 }
297
316
298 /// Returns whether the given revision exists in this revlog.
317 /// Returns whether the given revision exists in this revlog.
299 pub fn has_rev(&self, rev: Revision) -> bool {
318 pub fn has_rev(&self, rev: UncheckedRevision) -> bool {
300 self.index.get_entry(rev).is_some()
319 self.index.check_revision(rev).is_some()
301 }
320 }
302
321
303 /// Return the full data associated to a revision.
322 /// Return the full data associated to a revision.
@@ -307,12 +326,23 b' impl Revlog {'
307 /// snapshot to rebuild the final data.
326 /// snapshot to rebuild the final data.
308 pub fn get_rev_data(
327 pub fn get_rev_data(
309 &self,
328 &self,
329 rev: UncheckedRevision,
330 ) -> Result<Cow<[u8]>, RevlogError> {
331 if rev == NULL_REVISION.into() {
332 return Ok(Cow::Borrowed(&[]));
333 };
334 self.get_entry(rev)?.data()
335 }
336
337 /// [`Self::get_rev_data`] for checked revisions.
338 pub fn get_rev_data_for_checked_rev(
339 &self,
310 rev: Revision,
340 rev: Revision,
311 ) -> Result<Cow<[u8]>, RevlogError> {
341 ) -> Result<Cow<[u8]>, RevlogError> {
312 if rev == NULL_REVISION {
342 if rev == NULL_REVISION {
313 return Ok(Cow::Borrowed(&[]));
343 return Ok(Cow::Borrowed(&[]));
314 };
344 };
315 Ok(self.get_entry(rev)?.data()?)
345 self.get_entry_for_checked_rev(rev)?.data()
316 }
346 }
317
347
318 /// Check the hash of some given data against the recorded hash.
348 /// Check the hash of some given data against the recorded hash.
@@ -380,8 +410,7 b' impl Revlog {'
380 }
410 }
381 }
411 }
382
412
383 /// Get an entry of the revlog.
413 fn get_entry_for_checked_rev(
384 pub fn get_entry(
385 &self,
414 &self,
386 rev: Revision,
415 rev: Revision,
387 ) -> Result<RevlogEntry, RevlogError> {
416 ) -> Result<RevlogEntry, RevlogError> {
@@ -399,36 +428,60 b' impl Revlog {'
399 } else {
428 } else {
400 &self.data()[start..end]
429 &self.data()[start..end]
401 };
430 };
431 let base_rev = self
432 .index
433 .check_revision(index_entry.base_revision_or_base_of_delta_chain())
434 .ok_or_else(|| {
435 RevlogError::corrupted(format!(
436 "base revision for rev {} is invalid",
437 rev
438 ))
439 })?;
440 let p1 =
441 self.index.check_revision(index_entry.p1()).ok_or_else(|| {
442 RevlogError::corrupted(format!(
443 "p1 for rev {} is invalid",
444 rev
445 ))
446 })?;
447 let p2 =
448 self.index.check_revision(index_entry.p2()).ok_or_else(|| {
449 RevlogError::corrupted(format!(
450 "p2 for rev {} is invalid",
451 rev
452 ))
453 })?;
402 let entry = RevlogEntry {
454 let entry = RevlogEntry {
403 revlog: self,
455 revlog: self,
404 rev,
456 rev,
405 bytes: data,
457 bytes: data,
406 compressed_len: index_entry.compressed_len(),
458 compressed_len: index_entry.compressed_len(),
407 uncompressed_len: index_entry.uncompressed_len(),
459 uncompressed_len: index_entry.uncompressed_len(),
408 base_rev_or_base_of_delta_chain: if index_entry
460 base_rev_or_base_of_delta_chain: if base_rev == rev {
409 .base_revision_or_base_of_delta_chain()
410 == rev
411 {
412 None
461 None
413 } else {
462 } else {
414 Some(index_entry.base_revision_or_base_of_delta_chain())
463 Some(base_rev)
415 },
464 },
416 p1: index_entry.p1(),
465 p1,
417 p2: index_entry.p2(),
466 p2,
418 flags: index_entry.flags(),
467 flags: index_entry.flags(),
419 hash: *index_entry.hash(),
468 hash: *index_entry.hash(),
420 };
469 };
421 Ok(entry)
470 Ok(entry)
422 }
471 }
423
472
424 /// when resolving internal references within revlog, any errors
473 /// Get an entry of the revlog.
425 /// should be reported as corruption, instead of e.g. "invalid revision"
474 pub fn get_entry(
426 fn get_entry_internal(
427 &self,
475 &self,
428 rev: Revision,
476 rev: UncheckedRevision,
429 ) -> Result<RevlogEntry, HgError> {
477 ) -> Result<RevlogEntry, RevlogError> {
430 self.get_entry(rev)
478 if rev == NULL_REVISION.into() {
431 .map_err(|_| corrupted(format!("revision {} out of range", rev)))
479 return Ok(self.make_null_entry());
480 }
481 let rev = self.index.check_revision(rev).ok_or_else(|| {
482 RevlogError::corrupted(format!("rev {} is invalid", rev))
483 })?;
484 self.get_entry_for_checked_rev(rev)
432 }
485 }
433 }
486 }
434
487
@@ -486,7 +539,7 b" impl<'revlog> RevlogEntry<'revlog> {"
486 if self.p1 == NULL_REVISION {
539 if self.p1 == NULL_REVISION {
487 Ok(None)
540 Ok(None)
488 } else {
541 } else {
489 Ok(Some(self.revlog.get_entry(self.p1)?))
542 Ok(Some(self.revlog.get_entry_for_checked_rev(self.p1)?))
490 }
543 }
491 }
544 }
492
545
@@ -496,7 +549,7 b" impl<'revlog> RevlogEntry<'revlog> {"
496 if self.p2 == NULL_REVISION {
549 if self.p2 == NULL_REVISION {
497 Ok(None)
550 Ok(None)
498 } else {
551 } else {
499 Ok(Some(self.revlog.get_entry(self.p2)?))
552 Ok(Some(self.revlog.get_entry_for_checked_rev(self.p2)?))
500 }
553 }
501 }
554 }
502
555
@@ -527,7 +580,7 b" impl<'revlog> RevlogEntry<'revlog> {"
527 }
580 }
528
581
529 /// The data for this entry, after resolving deltas if any.
582 /// The data for this entry, after resolving deltas if any.
530 pub fn rawdata(&self) -> Result<Cow<'revlog, [u8]>, HgError> {
583 pub fn rawdata(&self) -> Result<Cow<'revlog, [u8]>, RevlogError> {
531 let mut entry = self.clone();
584 let mut entry = self.clone();
532 let mut delta_chain = vec![];
585 let mut delta_chain = vec![];
533
586
@@ -539,11 +592,11 b" impl<'revlog> RevlogEntry<'revlog> {"
539 while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain {
592 while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain {
540 entry = if uses_generaldelta {
593 entry = if uses_generaldelta {
541 delta_chain.push(entry);
594 delta_chain.push(entry);
542 self.revlog.get_entry_internal(base_rev)?
595 self.revlog.get_entry_for_checked_rev(base_rev)?
543 } else {
596 } else {
544 let base_rev = entry.rev - 1;
597 let base_rev = UncheckedRevision(entry.rev - 1);
545 delta_chain.push(entry);
598 delta_chain.push(entry);
546 self.revlog.get_entry_internal(base_rev)?
599 self.revlog.get_entry(base_rev)?
547 };
600 };
548 }
601 }
549
602
@@ -559,7 +612,7 b" impl<'revlog> RevlogEntry<'revlog> {"
559 fn check_data(
612 fn check_data(
560 &self,
613 &self,
561 data: Cow<'revlog, [u8]>,
614 data: Cow<'revlog, [u8]>,
562 ) -> Result<Cow<'revlog, [u8]>, HgError> {
615 ) -> Result<Cow<'revlog, [u8]>, RevlogError> {
563 if self.revlog.check_hash(
616 if self.revlog.check_hash(
564 self.p1,
617 self.p1,
565 self.p2,
618 self.p2,
@@ -571,22 +624,24 b" impl<'revlog> RevlogEntry<'revlog> {"
571 if (self.flags & REVISION_FLAG_ELLIPSIS) != 0 {
624 if (self.flags & REVISION_FLAG_ELLIPSIS) != 0 {
572 return Err(HgError::unsupported(
625 return Err(HgError::unsupported(
573 "ellipsis revisions are not supported by rhg",
626 "ellipsis revisions are not supported by rhg",
574 ));
627 )
628 .into());
575 }
629 }
576 Err(corrupted(format!(
630 Err(corrupted(format!(
577 "hash check failed for revision {}",
631 "hash check failed for revision {}",
578 self.rev
632 self.rev
579 )))
633 ))
634 .into())
580 }
635 }
581 }
636 }
582
637
583 pub fn data(&self) -> Result<Cow<'revlog, [u8]>, HgError> {
638 pub fn data(&self) -> Result<Cow<'revlog, [u8]>, RevlogError> {
584 let data = self.rawdata()?;
639 let data = self.rawdata()?;
585 if self.rev == NULL_REVISION {
640 if self.rev == NULL_REVISION {
586 return Ok(data);
641 return Ok(data);
587 }
642 }
588 if self.is_censored() {
643 if self.is_censored() {
589 return Err(HgError::CensoredNodeError);
644 return Err(HgError::CensoredNodeError.into());
590 }
645 }
591 self.check_data(data)
646 self.check_data(data)
592 }
647 }
@@ -705,13 +760,13 b' mod tests {'
705 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
760 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
706 assert!(revlog.is_empty());
761 assert!(revlog.is_empty());
707 assert_eq!(revlog.len(), 0);
762 assert_eq!(revlog.len(), 0);
708 assert!(revlog.get_entry(0).is_err());
763 assert!(revlog.get_entry(0.into()).is_err());
709 assert!(!revlog.has_rev(0));
764 assert!(!revlog.has_rev(0.into()));
710 assert_eq!(
765 assert_eq!(
711 revlog.rev_from_node(NULL_NODE.into()).unwrap(),
766 revlog.rev_from_node(NULL_NODE.into()).unwrap(),
712 NULL_REVISION
767 NULL_REVISION
713 );
768 );
714 let null_entry = revlog.get_entry(NULL_REVISION).ok().unwrap();
769 let null_entry = revlog.get_entry(NULL_REVISION.into()).ok().unwrap();
715 assert_eq!(null_entry.revision(), NULL_REVISION);
770 assert_eq!(null_entry.revision(), NULL_REVISION);
716 assert!(null_entry.data().unwrap().is_empty());
771 assert!(null_entry.data().unwrap().is_empty());
717 }
772 }
@@ -750,7 +805,7 b' mod tests {'
750 std::fs::write(temp.path().join("foo.i"), contents).unwrap();
805 std::fs::write(temp.path().join("foo.i"), contents).unwrap();
751 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
806 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
752
807
753 let entry0 = revlog.get_entry(0).ok().unwrap();
808 let entry0 = revlog.get_entry(0.into()).ok().unwrap();
754 assert_eq!(entry0.revision(), 0);
809 assert_eq!(entry0.revision(), 0);
755 assert_eq!(*entry0.node(), node0);
810 assert_eq!(*entry0.node(), node0);
756 assert!(!entry0.has_p1());
811 assert!(!entry0.has_p1());
@@ -761,7 +816,7 b' mod tests {'
761 let p2_entry = entry0.p2_entry().unwrap();
816 let p2_entry = entry0.p2_entry().unwrap();
762 assert!(p2_entry.is_none());
817 assert!(p2_entry.is_none());
763
818
764 let entry1 = revlog.get_entry(1).ok().unwrap();
819 let entry1 = revlog.get_entry(1.into()).ok().unwrap();
765 assert_eq!(entry1.revision(), 1);
820 assert_eq!(entry1.revision(), 1);
766 assert_eq!(*entry1.node(), node1);
821 assert_eq!(*entry1.node(), node1);
767 assert!(!entry1.has_p1());
822 assert!(!entry1.has_p1());
@@ -772,7 +827,7 b' mod tests {'
772 let p2_entry = entry1.p2_entry().unwrap();
827 let p2_entry = entry1.p2_entry().unwrap();
773 assert!(p2_entry.is_none());
828 assert!(p2_entry.is_none());
774
829
775 let entry2 = revlog.get_entry(2).ok().unwrap();
830 let entry2 = revlog.get_entry(2.into()).ok().unwrap();
776 assert_eq!(entry2.revision(), 2);
831 assert_eq!(entry2.revision(), 2);
777 assert_eq!(*entry2.node(), node2);
832 assert_eq!(*entry2.node(), node2);
778 assert!(entry2.has_p1());
833 assert!(entry2.has_p1());
@@ -817,7 +872,7 b' mod tests {'
817 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
872 let revlog = Revlog::open(&vfs, "foo.i", None, false).unwrap();
818
873
819 // accessing the data shows the corruption
874 // accessing the data shows the corruption
820 revlog.get_entry(0).unwrap().data().unwrap_err();
875 revlog.get_entry(0.into()).unwrap().data().unwrap_err();
821
876
822 assert_eq!(revlog.rev_from_node(NULL_NODE.into()).unwrap(), -1);
877 assert_eq!(revlog.rev_from_node(NULL_NODE.into()).unwrap(), -1);
823 assert_eq!(revlog.rev_from_node(node0.into()).unwrap(), 0);
878 assert_eq!(revlog.rev_from_node(node0.into()).unwrap(), 0);
@@ -12,6 +12,8 b''
12 //! Following existing implicit conventions, the "nodemap" terminology
12 //! Following existing implicit conventions, the "nodemap" terminology
13 //! is used in a more abstract context.
13 //! is used in a more abstract context.
14
14
15 use crate::UncheckedRevision;
16
15 use super::{
17 use super::{
16 node::NULL_NODE, Node, NodePrefix, Revision, RevlogIndex, NULL_REVISION,
18 node::NULL_NODE, Node, NodePrefix, Revision, RevlogIndex, NULL_REVISION,
17 };
19 };
@@ -30,7 +32,7 b' pub enum NodeMapError {'
30 /// This can be returned by methods meant for (at most) one match.
32 /// This can be returned by methods meant for (at most) one match.
31 MultipleResults,
33 MultipleResults,
32 /// A `Revision` stored in the nodemap could not be found in the index
34 /// A `Revision` stored in the nodemap could not be found in the index
33 RevisionNotInIndex(Revision),
35 RevisionNotInIndex(UncheckedRevision),
34 }
36 }
35
37
36 /// Mapping system from Mercurial nodes to revision numbers.
38 /// Mapping system from Mercurial nodes to revision numbers.
@@ -125,7 +127,9 b' type RawElement = unaligned::I32Be;'
125 /// use.
127 /// use.
126 #[derive(Clone, Debug, Eq, PartialEq)]
128 #[derive(Clone, Debug, Eq, PartialEq)]
127 enum Element {
129 enum Element {
128 Rev(Revision),
130 // This is not a Mercurial revision. It's a `i32` because this is the
131 // right type for this structure.
132 Rev(i32),
129 Block(usize),
133 Block(usize),
130 None,
134 None,
131 }
135 }
@@ -245,17 +249,21 b' impl Index<usize> for NodeTree {'
245 fn has_prefix_or_none(
249 fn has_prefix_or_none(
246 idx: &impl RevlogIndex,
250 idx: &impl RevlogIndex,
247 prefix: NodePrefix,
251 prefix: NodePrefix,
248 rev: Revision,
252 rev: UncheckedRevision,
249 ) -> Result<Option<Revision>, NodeMapError> {
253 ) -> Result<Option<Revision>, NodeMapError> {
250 idx.node(rev)
254 match idx.check_revision(rev) {
255 Some(checked) => idx
256 .node(checked)
251 .ok_or(NodeMapError::RevisionNotInIndex(rev))
257 .ok_or(NodeMapError::RevisionNotInIndex(rev))
252 .map(|node| {
258 .map(|node| {
253 if prefix.is_prefix_of(node) {
259 if prefix.is_prefix_of(node) {
254 Some(rev)
260 Some(checked)
255 } else {
261 } else {
256 None
262 None
257 }
263 }
258 })
264 }),
265 None => Err(NodeMapError::RevisionNotInIndex(rev)),
266 }
259 }
267 }
260
268
261 /// validate that the candidate's node starts indeed with given prefix,
269 /// validate that the candidate's node starts indeed with given prefix,
@@ -266,7 +274,7 b' fn has_prefix_or_none('
266 fn validate_candidate(
274 fn validate_candidate(
267 idx: &impl RevlogIndex,
275 idx: &impl RevlogIndex,
268 prefix: NodePrefix,
276 prefix: NodePrefix,
269 candidate: (Option<Revision>, usize),
277 candidate: (Option<UncheckedRevision>, usize),
270 ) -> Result<(Option<Revision>, usize), NodeMapError> {
278 ) -> Result<(Option<Revision>, usize), NodeMapError> {
271 let (rev, steps) = candidate;
279 let (rev, steps) = candidate;
272 if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) {
280 if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) {
@@ -384,6 +392,8 b' impl NodeTree {'
384 /// be inferred from
392 /// be inferred from
385 /// the `NodeTree` data is that `rev` is the revision with the longest
393 /// the `NodeTree` data is that `rev` is the revision with the longest
386 /// common node prefix with the given prefix.
394 /// common node prefix with the given prefix.
395 /// We return an [`UncheckedRevision`] because we have no guarantee that
396 /// the revision we found is valid for the index.
387 ///
397 ///
388 /// The second returned value is the size of the smallest subprefix
398 /// The second returned value is the size of the smallest subprefix
389 /// of `prefix` that would give the same result, i.e. not the
399 /// of `prefix` that would give the same result, i.e. not the
@@ -392,7 +402,7 b' impl NodeTree {'
392 fn lookup(
402 fn lookup(
393 &self,
403 &self,
394 prefix: NodePrefix,
404 prefix: NodePrefix,
395 ) -> Result<(Option<Revision>, usize), NodeMapError> {
405 ) -> Result<(Option<UncheckedRevision>, usize), NodeMapError> {
396 for (i, visit_item) in self.visit(prefix).enumerate() {
406 for (i, visit_item) in self.visit(prefix).enumerate() {
397 if let Some(opt) = visit_item.final_revision() {
407 if let Some(opt) = visit_item.final_revision() {
398 return Ok((opt, i + 1));
408 return Ok((opt, i + 1));
@@ -464,9 +474,9 b' impl NodeTree {'
464 self.mutable_block(deepest.block_idx);
474 self.mutable_block(deepest.block_idx);
465
475
466 if let Element::Rev(old_rev) = deepest.element {
476 if let Element::Rev(old_rev) = deepest.element {
467 let old_node = index
477 let old_node = index.node(old_rev).ok_or_else(|| {
468 .node(old_rev)
478 NodeMapError::RevisionNotInIndex(old_rev.into())
469 .ok_or(NodeMapError::RevisionNotInIndex(old_rev))?;
479 })?;
470 if old_node == node {
480 if old_node == node {
471 return Ok(()); // avoid creating lots of useless blocks
481 return Ok(()); // avoid creating lots of useless blocks
472 }
482 }
@@ -623,13 +633,13 b" impl<'n> Iterator for NodeTreeVisitor<'n"
623
633
624 impl NodeTreeVisitItem {
634 impl NodeTreeVisitItem {
625 // Return `Some(opt)` if this item is final, with `opt` being the
635 // Return `Some(opt)` if this item is final, with `opt` being the
626 // `Revision` that it may represent.
636 // `UncheckedRevision` that it may represent.
627 //
637 //
628 // If the item is not terminal, return `None`
638 // If the item is not terminal, return `None`
629 fn final_revision(&self) -> Option<Option<Revision>> {
639 fn final_revision(&self) -> Option<Option<UncheckedRevision>> {
630 match self.element {
640 match self.element {
631 Element::Block(_) => None,
641 Element::Block(_) => None,
632 Element::Rev(r) => Some(Some(r)),
642 Element::Rev(r) => Some(Some(r.into())),
633 Element::None => Some(None),
643 Element::None => Some(None),
634 }
644 }
635 }
645 }
@@ -733,16 +743,20 b' mod tests {'
733 assert_eq!(block.get(4), Element::Rev(1));
743 assert_eq!(block.get(4), Element::Rev(1));
734 }
744 }
735
745
736 type TestIndex = HashMap<Revision, Node>;
746 type TestIndex = HashMap<UncheckedRevision, Node>;
737
747
738 impl RevlogIndex for TestIndex {
748 impl RevlogIndex for TestIndex {
739 fn node(&self, rev: Revision) -> Option<&Node> {
749 fn node(&self, rev: Revision) -> Option<&Node> {
740 self.get(&rev)
750 self.get(&rev.into())
741 }
751 }
742
752
743 fn len(&self) -> usize {
753 fn len(&self) -> usize {
744 self.len()
754 self.len()
745 }
755 }
756
757 fn check_revision(&self, rev: UncheckedRevision) -> Option<Revision> {
758 self.get(&rev).map(|_| rev.0)
759 }
746 }
760 }
747
761
748 /// Pad hexadecimal Node prefix with zeros on the right
762 /// Pad hexadecimal Node prefix with zeros on the right
@@ -756,7 +770,7 b' mod tests {'
756
770
757 /// Pad hexadecimal Node prefix with zeros on the right, then insert
771 /// Pad hexadecimal Node prefix with zeros on the right, then insert
758 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
772 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
759 idx.insert(rev, pad_node(hex));
773 idx.insert(rev.into(), pad_node(hex));
760 }
774 }
761
775
762 fn sample_nodetree() -> NodeTree {
776 fn sample_nodetree() -> NodeTree {
@@ -796,7 +810,7 b' mod tests {'
796 assert_eq!(nt.find_bin(&idx, hex("ab"))?, None);
810 assert_eq!(nt.find_bin(&idx, hex("ab"))?, None);
797
811
798 // and with full binary Nodes
812 // and with full binary Nodes
799 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
813 assert_eq!(nt.find_node(&idx, idx.get(&1.into()).unwrap())?, Some(1));
800 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
814 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
801 assert_eq!(nt.find_node(&idx, &unknown)?, None);
815 assert_eq!(nt.find_node(&idx, &unknown)?, None);
802 Ok(())
816 Ok(())
@@ -857,14 +871,15 b' mod tests {'
857 }
871 }
858 }
872 }
859
873
860 fn insert(
874 fn insert(&mut self, rev: i32, hex: &str) -> Result<(), NodeMapError> {
861 &mut self,
862 rev: Revision,
863 hex: &str,
864 ) -> Result<(), NodeMapError> {
865 let node = pad_node(hex);
875 let node = pad_node(hex);
876 let rev: UncheckedRevision = rev.into();
866 self.index.insert(rev, node);
877 self.index.insert(rev, node);
867 self.nt.insert(&self.index, &node, rev)?;
878 self.nt.insert(
879 &self.index,
880 &node,
881 self.index.check_revision(rev).unwrap(),
882 )?;
868 Ok(())
883 Ok(())
869 }
884 }
870
885
@@ -971,9 +986,9 b' mod tests {'
971 let node0 = Node::from_hex(&node0_hex).unwrap();
986 let node0 = Node::from_hex(&node0_hex).unwrap();
972 let node1 = Node::from_hex(&node1_hex).unwrap();
987 let node1 = Node::from_hex(&node1_hex).unwrap();
973
988
974 idx.insert(0, node0);
989 idx.insert(0.into(), node0);
975 nt.insert(idx, &node0, 0)?;
990 nt.insert(idx, &node0, 0)?;
976 idx.insert(1, node1);
991 idx.insert(1.into(), node1);
977 nt.insert(idx, &node1, 1)?;
992 nt.insert(idx, &node1, 1)?;
978
993
979 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
994 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
@@ -53,7 +53,7 b' pub fn resolve_rev_number_or_hex_prefix('
53 if let Ok(integer) = input.parse::<i32>() {
53 if let Ok(integer) = input.parse::<i32>() {
54 if integer.to_string() == input
54 if integer.to_string() == input
55 && integer >= 0
55 && integer >= 0
56 && revlog.has_rev(integer)
56 && revlog.has_rev(integer.into())
57 {
57 {
58 return Ok(integer);
58 return Ok(integer);
59 }
59 }
@@ -18,7 +18,7 b' use cpython::{'
18 use hg::{
18 use hg::{
19 nodemap::{Block, NodeMapError, NodeTree},
19 nodemap::{Block, NodeMapError, NodeTree},
20 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
20 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
21 Revision,
21 Revision, UncheckedRevision,
22 };
22 };
23 use std::cell::RefCell;
23 use std::cell::RefCell;
24
24
@@ -252,7 +252,7 b' py_class!(pub class MixedIndex |py| {'
252 // Note that we don't seem to have a direct way to call
252 // Note that we don't seem to have a direct way to call
253 // PySequence_GetItem (does the job), which would possibly be better
253 // PySequence_GetItem (does the job), which would possibly be better
254 // for performance
254 // for performance
255 let key = match key.extract::<Revision>(py) {
255 let key = match key.extract::<i32>(py) {
256 Ok(rev) => rev.to_py_object(py).into_object(),
256 Ok(rev) => rev.to_py_object(py).into_object(),
257 Err(_) => key,
257 Err(_) => key,
258 };
258 };
@@ -268,7 +268,7 b' py_class!(pub class MixedIndex |py| {'
268 // this is an equivalent implementation of the index_contains()
268 // this is an equivalent implementation of the index_contains()
269 // defined in revlog.c
269 // defined in revlog.c
270 let cindex = self.cindex(py).borrow();
270 let cindex = self.cindex(py).borrow();
271 match item.extract::<Revision>(py) {
271 match item.extract::<i32>(py) {
272 Ok(rev) => {
272 Ok(rev) => {
273 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
273 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
274 }
274 }
@@ -448,9 +448,12 b' impl MixedIndex {'
448 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
448 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
449
449
450 let data_tip =
450 let data_tip =
451 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
451 docket.getattr(py, "tip_rev")?.extract::<i32>(py)?.into();
452 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
452 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
453 let idx = self.cindex(py).borrow();
453 let idx = self.cindex(py).borrow();
454 let data_tip = idx.check_revision(data_tip).ok_or_else(|| {
455 nodemap_error(py, NodeMapError::RevisionNotInIndex(data_tip))
456 })?;
454 let current_tip = idx.len();
457 let current_tip = idx.len();
455
458
456 for r in (data_tip + 1)..current_tip as Revision {
459 for r in (data_tip + 1)..current_tip as Revision {
@@ -479,7 +482,7 b' fn revlog_error(py: Python) -> PyErr {'
479 }
482 }
480 }
483 }
481
484
482 fn rev_not_in_index(py: Python, rev: Revision) -> PyErr {
485 fn rev_not_in_index(py: Python, rev: UncheckedRevision) -> PyErr {
483 PyErr::new::<ValueError, _>(
486 PyErr::new::<ValueError, _>(
484 py,
487 py,
485 format!(
488 format!(
General Comments 0
You need to be logged in to leave comments. Login now