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