comparison rust/hg-core/src/revlog/nodemap.rs @ 44387:00d251d32007

rust-nodemap: special case for prefixes of NULL_NODE We have to behave as though NULL_NODE was stored in the node tree, although we don't store it. Differential Revision: https://phab.mercurial-scm.org/D7798
author Georges Racinet <georges.racinet@octobus.net>
date Tue, 18 Feb 2020 19:11:16 +0100
parents a98ba6983a63
children 5ac1eecc9c64
comparison
equal deleted inserted replaced
44386:8f7c6656ac79 44387:00d251d32007
11 //! 11 //!
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 super::{ 15 use super::{
16 Node, NodeError, NodePrefix, NodePrefixRef, Revision, RevlogIndex, 16 node::NULL_NODE, Node, NodeError, NodePrefix, NodePrefixRef, Revision,
17 RevlogIndex, NULL_REVISION,
17 }; 18 };
18 19
19 use std::fmt; 20 use std::fmt;
20 use std::mem; 21 use std::mem;
21 use std::ops::Deref; 22 use std::ops::Deref;
268 None 269 None
269 } 270 }
270 }) 271 })
271 } 272 }
272 273
274 /// validate that the candidate's node starts indeed with given prefix,
275 /// and treat ambiguities related to `NULL_REVISION`.
276 ///
277 /// From the data in the NodeTree, one can only conclude that some
278 /// revision is the only one for a *subprefix* of the one being looked up.
279 fn validate_candidate(
280 idx: &impl RevlogIndex,
281 prefix: NodePrefixRef,
282 rev: Option<Revision>,
283 ) -> Result<Option<Revision>, NodeMapError> {
284 if prefix.is_prefix_of(&NULL_NODE) {
285 // NULL_REVISION always matches a prefix made only of zeros
286 // and any other *valid* result is an ambiguity
287 match rev {
288 None => Ok(Some(NULL_REVISION)),
289 Some(r) => match has_prefix_or_none(idx, prefix, r)? {
290 None => Ok(Some(NULL_REVISION)),
291 _ => Err(NodeMapError::MultipleResults),
292 },
293 }
294 } else {
295 rev.map_or(Ok(None), |r| has_prefix_or_none(idx, prefix, r))
296 }
297 }
298
273 impl NodeTree { 299 impl NodeTree {
274 /// Initiate a NodeTree from an immutable slice-like of `Block` 300 /// Initiate a NodeTree from an immutable slice-like of `Block`
275 /// 301 ///
276 /// We keep `readonly` and clone its root block if it isn't empty. 302 /// We keep `readonly` and clone its root block if it isn't empty.
277 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self { 303 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
359 fn is_empty(&self) -> bool { 385 fn is_empty(&self) -> bool {
360 false 386 false
361 } 387 }
362 388
363 /// Main working method for `NodeTree` searches 389 /// Main working method for `NodeTree` searches
364 ///
365 /// This partial implementation lacks special cases for NULL_REVISION
366 fn lookup<'p>( 390 fn lookup<'p>(
367 &self, 391 &self,
368 prefix: NodePrefixRef<'p>, 392 prefix: NodePrefixRef<'p>,
369 ) -> Result<Option<Revision>, NodeMapError> { 393 ) -> Result<Option<Revision>, NodeMapError> {
370 for visit_item in self.visit(prefix) { 394 for visit_item in self.visit(prefix) {
611 fn find_bin<'a>( 635 fn find_bin<'a>(
612 &self, 636 &self,
613 idx: &impl RevlogIndex, 637 idx: &impl RevlogIndex,
614 prefix: NodePrefixRef<'a>, 638 prefix: NodePrefixRef<'a>,
615 ) -> Result<Option<Revision>, NodeMapError> { 639 ) -> Result<Option<Revision>, NodeMapError> {
616 self.lookup(prefix.clone()).and_then(|opt| { 640 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
617 opt.map_or(Ok(None), |rev| has_prefix_or_none(idx, prefix, rev))
618 })
619 } 641 }
620 } 642 }
621 643
622 #[cfg(test)] 644 #[cfg(test)]
623 mod tests { 645 mod tests {
746 768
747 let nt = sample_nodetree(); 769 let nt = sample_nodetree();
748 770
749 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults)); 771 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults));
750 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9))); 772 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
751 assert_eq!(nt.find_hex(&idx, "00"), Ok(Some(0))); 773 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
752 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0))); 774 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
775 assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION)));
753 } 776 }
754 777
755 #[test] 778 #[test]
756 fn test_mutated_find() -> Result<(), NodeMapError> { 779 fn test_mutated_find() -> Result<(), NodeMapError> {
757 let mut idx = TestIndex::new(); 780 let mut idx = TestIndex::new();
766 growable: vec![block![0: Rev(1), 5: Rev(3)]], 789 growable: vec![block![0: Rev(1), 5: Rev(3)]],
767 root: block![0: Block(1), 1:Block(3), 12: Rev(2)], 790 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
768 }; 791 };
769 assert_eq!(nt.find_hex(&idx, "10")?, Some(1)); 792 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
770 assert_eq!(nt.find_hex(&idx, "c")?, Some(2)); 793 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
771 assert_eq!(nt.find_hex(&idx, "00")?, Some(0)); 794 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
795 assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION));
772 assert_eq!(nt.find_hex(&idx, "01")?, Some(9)); 796 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
773 Ok(()) 797 Ok(())
774 } 798 }
775 799
776 struct TestNtIndex { 800 struct TestNtIndex {