##// END OF EJS Templates
rust-cpython: binding for LazyAncestors...
Georges Racinet -
r41149:b31a41f2 default
parent child Browse files
Show More
@@ -13,8 +13,8 b' use cpython::{'
13 };
13 };
14 use exceptions::GraphError;
14 use exceptions::GraphError;
15 use hg;
15 use hg;
16 use hg::AncestorsIterator as CoreIterator;
17 use hg::Revision;
16 use hg::Revision;
17 use hg::{AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy};
18 use std::cell::RefCell;
18 use std::cell::RefCell;
19
19
20 /// Utility function to convert a Python iterable into a Vec<Revision>
20 /// Utility function to convert a Python iterable into a Vec<Revision>
@@ -70,6 +70,37 b' impl AncestorsIterator {'
70 }
70 }
71 }
71 }
72
72
73 py_class!(class LazyAncestors |py| {
74 data inner: RefCell<Box<CoreLazy<Index>>>;
75
76 def __contains__(&self, rev: Revision) -> PyResult<bool> {
77 self.inner(py)
78 .borrow_mut()
79 .contains(rev)
80 .map_err(|e| GraphError::pynew(py, e))
81 }
82
83 def __iter__(&self) -> PyResult<AncestorsIterator> {
84 AncestorsIterator::from_inner(py, self.inner(py).borrow().iter())
85 }
86
87 def __bool__(&self) -> PyResult<bool> {
88 Ok(!self.inner(py).borrow().is_empty())
89 }
90
91 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
92 inclusive: bool) -> PyResult<Self> {
93 let initvec = reviter_to_revvec(py, initrevs)?;
94
95 let lazy =
96 CoreLazy::new(Index::new(py, index)?, initvec, stoprev, inclusive)
97 .map_err(|e| GraphError::pynew(py, e))?;
98
99 Self::create_instance(py, RefCell::new(Box::new(lazy)))
100 }
101
102 });
103
73 /// Create the module, with __package__ given from parent
104 /// Create the module, with __package__ given from parent
74 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
105 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
75 let dotted_name = &format!("{}.ancestor", package);
106 let dotted_name = &format!("{}.ancestor", package);
@@ -81,6 +112,7 b' pub fn init_module(py: Python, package: '
81 "Generic DAG ancestor algorithms - Rust implementation",
112 "Generic DAG ancestor algorithms - Rust implementation",
82 )?;
113 )?;
83 m.add_class::<AncestorsIterator>(py)?;
114 m.add_class::<AncestorsIterator>(py)?;
115 m.add_class::<LazyAncestors>(py)?;
84
116
85 let sys = PyModule::import(py, "sys")?;
117 let sys = PyModule::import(py, "sys")?;
86 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
118 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
@@ -9,7 +9,10 b' except ImportError:'
9 rustext = None
9 rustext = None
10 else:
10 else:
11 # this would fail already without appropriate ancestor.__package__
11 # this would fail already without appropriate ancestor.__package__
12 from mercurial.rustext.ancestor import AncestorsIterator
12 from mercurial.rustext.ancestor import (
13 AncestorsIterator,
14 LazyAncestors
15 )
13
16
14 try:
17 try:
15 from mercurial.cext import parsers as cparsers
18 from mercurial.cext import parsers as cparsers
@@ -71,6 +74,37 b' class rustancestorstest(unittest.TestCas'
71 ait = AncestorsIterator(idx, [3], 0, False)
74 ait = AncestorsIterator(idx, [3], 0, False)
72 self.assertEqual([r for r in ait], [2, 1, 0])
75 self.assertEqual([r for r in ait], [2, 1, 0])
73
76
77 def testlazyancestors(self):
78 idx = self.parseindex()
79 start_count = sys.getrefcount(idx) # should be 2 (see Python doc)
80 self.assertEqual({i: (r[5], r[6]) for i, r in enumerate(idx)},
81 {0: (-1, -1),
82 1: (0, -1),
83 2: (1, -1),
84 3: (2, -1)})
85 lazy = LazyAncestors(idx, [3], 0, True)
86 # we have two more references to the index:
87 # - in its inner iterator for __contains__ and __bool__
88 # - in the LazyAncestors instance itself (to spawn new iterators)
89 self.assertEqual(sys.getrefcount(idx), start_count + 2)
90
91 self.assertTrue(2 in lazy)
92 self.assertTrue(bool(lazy))
93 self.assertEqual(list(lazy), [3, 2, 1, 0])
94 # a second time to validate that we spawn new iterators
95 self.assertEqual(list(lazy), [3, 2, 1, 0])
96
97 # now let's watch the refcounts closer
98 ait = iter(lazy)
99 self.assertEqual(sys.getrefcount(idx), start_count + 3)
100 del ait
101 self.assertEqual(sys.getrefcount(idx), start_count + 2)
102 del lazy
103 self.assertEqual(sys.getrefcount(idx), start_count)
104
105 # let's check bool for an empty one
106 self.assertFalse(LazyAncestors(idx, [0], 0, False))
107
74 def testrefcount(self):
108 def testrefcount(self):
75 idx = self.parseindex()
109 idx = self.parseindex()
76 start_count = sys.getrefcount(idx)
110 start_count = sys.getrefcount(idx)
@@ -87,7 +121,7 b' class rustancestorstest(unittest.TestCas'
87 # and removing ref to the index after iterator init is no issue
121 # and removing ref to the index after iterator init is no issue
88 ait = AncestorsIterator(idx, [3], 0, True)
122 ait = AncestorsIterator(idx, [3], 0, True)
89 del idx
123 del idx
90 self.assertEqual([r for r in ait], [3, 2, 1, 0])
124 self.assertEqual(list(ait), [3, 2, 1, 0])
91
125
92 def testgrapherror(self):
126 def testgrapherror(self):
93 data = (data_non_inlined[:64 + 27] +
127 data = (data_non_inlined[:64 + 27] +
General Comments 0
You need to be logged in to leave comments. Login now