##// END OF EJS Templates
rust: core implementation for lazyancestors...
Georges Racinet -
r41084:ef54bd33 default
parent child Browse files
Show More
@@ -25,6 +25,15 b' pub struct AncestorsIterator<G: Graph> {'
25 stoprev: Revision,
25 stoprev: Revision,
26 }
26 }
27
27
28 /// Lazy ancestors set, backed by AncestorsIterator
29 pub struct LazyAncestors<G: Graph + Clone> {
30 graph: G,
31 containsiter: AncestorsIterator<G>,
32 initrevs: Vec<Revision>,
33 stoprev: Revision,
34 inclusive: bool,
35 }
36
28 pub struct MissingAncestors<G: Graph> {
37 pub struct MissingAncestors<G: Graph> {
29 graph: G,
38 graph: G,
30 bases: HashSet<Revision>,
39 bases: HashSet<Revision>,
@@ -98,9 +107,31 b' impl<G: Graph> AncestorsIterator<G> {'
98 }
107 }
99 Ok(false)
108 Ok(false)
100 }
109 }
110
111 pub fn peek(&self) -> Option<Revision> {
112 self.visit.peek().map(|&r| r)
113 }
114
115 /// Tell if the iterator is about an empty set
116 ///
117 /// The result does not depend whether the iterator has been consumed
118 /// or not.
119 /// This is mostly meant for iterators backing a lazy ancestors set
120 pub fn is_empty(&self) -> bool {
121 if self.visit.len() > 0 {
122 return false;
123 }
124 if self.seen.len() > 1 {
125 return false;
126 }
127 // at this point, the seen set is at most a singleton.
128 // If not `self.inclusive`, it's still possible that it has only
129 // the null revision
130 self.seen.is_empty() || self.seen.contains(&NULL_REVISION)
131 }
101 }
132 }
102
133
103 /// Main implementation.
134 /// Main implementation for the iterator
104 ///
135 ///
105 /// The algorithm is the same as in `_lazyancestorsiter()` from `ancestors.py`
136 /// The algorithm is the same as in `_lazyancestorsiter()` from `ancestors.py`
106 /// with a few non crucial differences:
137 /// with a few non crucial differences:
@@ -137,6 +168,49 b' impl<G: Graph> Iterator for AncestorsIte'
137 }
168 }
138 }
169 }
139
170
171 impl<G: Graph + Clone> LazyAncestors<G> {
172 pub fn new(
173 graph: G,
174 initrevs: impl IntoIterator<Item = Revision>,
175 stoprev: Revision,
176 inclusive: bool,
177 ) -> Result<Self, GraphError> {
178 let v: Vec<Revision> = initrevs.into_iter().collect();
179 Ok(LazyAncestors {
180 graph: graph.clone(),
181 containsiter: AncestorsIterator::new(
182 graph,
183 v.iter().cloned(),
184 stoprev,
185 inclusive,
186 )?,
187 initrevs: v,
188 stoprev: stoprev,
189 inclusive: inclusive,
190 })
191 }
192
193 pub fn contains(&mut self, rev: Revision) -> Result<bool, GraphError> {
194 self.containsiter.contains(rev)
195 }
196
197 pub fn is_empty(&self) -> bool {
198 self.containsiter.is_empty()
199 }
200
201 pub fn iter(&self) -> AncestorsIterator<G> {
202 // the arguments being the same as for self.containsiter, we know
203 // for sure that AncestorsIterator constructor can't fail
204 AncestorsIterator::new(
205 self.graph.clone(),
206 self.initrevs.iter().cloned(),
207 self.stoprev,
208 self.inclusive,
209 )
210 .unwrap()
211 }
212 }
213
140 impl<G: Graph> MissingAncestors<G> {
214 impl<G: Graph> MissingAncestors<G> {
141 pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self {
215 pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self {
142 let mut bases: HashSet<Revision> = bases.into_iter().collect();
216 let mut bases: HashSet<Revision> = bases.into_iter().collect();
@@ -407,7 +481,40 b' mod tests {'
407 assert!(!lazy.contains(NULL_REVISION).unwrap());
481 assert!(!lazy.contains(NULL_REVISION).unwrap());
408 }
482 }
409
483
484 #[test]
485 fn test_peek() {
486 let mut iter =
487 AncestorsIterator::new(Stub, vec![10], 0, true).unwrap();
488 // peek() gives us the next value
489 assert_eq!(iter.peek(), Some(10));
490 // but it's not been consumed
491 assert_eq!(iter.next(), Some(Ok(10)));
492 // and iteration resumes normally
493 assert_eq!(iter.next(), Some(Ok(5)));
494
495 // let's drain the iterator to test peek() at the end
496 while iter.next().is_some() {}
497 assert_eq!(iter.peek(), None);
498 }
499
500 #[test]
501 fn test_empty() {
502 let mut iter =
503 AncestorsIterator::new(Stub, vec![10], 0, true).unwrap();
504 assert!(!iter.is_empty());
505 while iter.next().is_some() {}
506 assert!(!iter.is_empty());
507
508 let iter = AncestorsIterator::new(Stub, vec![], 0, true).unwrap();
509 assert!(iter.is_empty());
510
511 // case where iter.seen == {NULL_REVISION}
512 let iter = AncestorsIterator::new(Stub, vec![0], 0, false).unwrap();
513 assert!(iter.is_empty());
514 }
515
410 /// A corrupted Graph, supporting error handling tests
516 /// A corrupted Graph, supporting error handling tests
517 #[derive(Clone, Debug)]
411 struct Corrupted;
518 struct Corrupted;
412
519
413 impl Graph for Corrupted {
520 impl Graph for Corrupted {
@@ -437,6 +544,39 b' mod tests {'
437 }
544 }
438
545
439 #[test]
546 #[test]
547 fn test_lazy_iter_contains() {
548 let mut lazy =
549 LazyAncestors::new(Stub, vec![11, 13], 0, false).unwrap();
550
551 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
552 // compare with iterator tests on the same initial revisions
553 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
554
555 // contains() results are correct, unaffected by the fact that
556 // we consumed entirely an iterator out of lazy
557 assert_eq!(lazy.contains(2), Ok(true));
558 assert_eq!(lazy.contains(9), Ok(false));
559 }
560
561 #[test]
562 fn test_lazy_contains_iter() {
563 let mut lazy =
564 LazyAncestors::new(Stub, vec![11, 13], 0, false).unwrap(); // reminder: [8, 7, 4, 3, 2, 1, 0]
565
566 assert_eq!(lazy.contains(2), Ok(true));
567 assert_eq!(lazy.contains(6), Ok(false));
568
569 // after consumption of 2 by the inner iterator, results stay
570 // consistent
571 assert_eq!(lazy.contains(2), Ok(true));
572 assert_eq!(lazy.contains(5), Ok(false));
573
574 // iter() still gives us a fresh iterator
575 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
576 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
577 }
578
579 #[test]
440 /// Test constructor, add/get bases
580 /// Test constructor, add/get bases
441 fn test_missing_bases() {
581 fn test_missing_bases() {
442 let mut missing_ancestors =
582 let mut missing_ancestors =
@@ -3,7 +3,7 b''
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5 mod ancestors;
5 mod ancestors;
6 pub use ancestors::{AncestorsIterator, MissingAncestors};
6 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
7
7
8 /// Mercurial revision numbers
8 /// Mercurial revision numbers
9 ///
9 ///
@@ -15,7 +15,7 b' extern crate python27_sys as python_sys;'
15 extern crate python3_sys as python_sys;
15 extern crate python3_sys as python_sys;
16
16
17 use self::python_sys::PyCapsule_Import;
17 use self::python_sys::PyCapsule_Import;
18 use cpython::{PyErr, PyObject, PyResult, Python};
18 use cpython::{PyClone, PyErr, PyObject, PyResult, Python};
19 use hg::{Graph, GraphError, Revision};
19 use hg::{Graph, GraphError, Revision};
20 use libc::c_int;
20 use libc::c_int;
21 use std::ffi::CStr;
21 use std::ffi::CStr;
@@ -59,7 +59,6 b' type IndexParentsFn = unsafe extern "C" '
59 /// the core API, that would be tied to `GILGuard` / `Python<'p>`
59 /// the core API, that would be tied to `GILGuard` / `Python<'p>`
60 /// in the case of the `cpython` crate bindings yet could leave room for other
60 /// in the case of the `cpython` crate bindings yet could leave room for other
61 /// mechanisms in other contexts.
61 /// mechanisms in other contexts.
62
63 pub struct Index {
62 pub struct Index {
64 index: PyObject,
63 index: PyObject,
65 parents: IndexParentsFn,
64 parents: IndexParentsFn,
@@ -74,6 +73,16 b' impl Index {'
74 }
73 }
75 }
74 }
76
75
76 impl Clone for Index {
77 fn clone(&self) -> Self {
78 let guard = Python::acquire_gil();
79 Index {
80 index: self.index.clone_ref(guard.python()),
81 parents: self.parents.clone(),
82 }
83 }
84 }
85
77 impl Graph for Index {
86 impl Graph for Index {
78 /// wrap a call to the C extern parents function
87 /// wrap a call to the C extern parents function
79 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
88 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
General Comments 0
You need to be logged in to leave comments. Login now