##// END OF EJS Templates
rust-index: add a struct wrapping the C index...
Georges Racinet -
r44413:b69d5f3a default
parent child Browse files
Show More
@@ -0,0 +1,34 b''
1 from __future__ import absolute_import
2 import unittest
3
4 try:
5 from mercurial import rustext
6
7 rustext.__name__ # trigger immediate actual import
8 except ImportError:
9 rustext = None
10 else:
11 from mercurial.rustext import revlog
12
13 from mercurial.testing import revlog as revlogtesting
14
15
16 @unittest.skipIf(
17 rustext is None, "rustext module revlog relies on is not available",
18 )
19 class RustRevlogIndexTest(revlogtesting.RevlogBasedTestBase):
20 def test_heads(self):
21 idx = self.parseindex()
22 rustidx = revlog.MixedIndex(idx)
23 self.assertEqual(rustidx.headrevs(), idx.headrevs())
24
25 def test_len(self):
26 idx = self.parseindex()
27 rustidx = revlog.MixedIndex(idx)
28 self.assertEqual(len(rustidx), len(idx))
29
30
31 if __name__ == '__main__':
32 import silenttestrunner
33
34 silenttestrunner.main(__name__)
@@ -50,6 +50,7 b' py_module_initializer!(rustext, initrust'
50 m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?;
50 m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?;
51 m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?;
51 m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?;
52 m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?;
52 m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?;
53 m.add(py, "revlog", revlog::init_module(py, &dotted_name)?)?;
53 m.add(
54 m.add(
54 py,
55 py,
55 "filepatterns",
56 "filepatterns",
@@ -6,7 +6,12 b''
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::cindex;
8 use crate::cindex;
9 use cpython::{PyObject, PyResult, Python};
9 use cpython::{
10 ObjectProtocol, PyDict, PyModule, PyObject, PyResult, PyTuple, Python,
11 PythonObject, ToPyObject,
12 };
13 use hg::Revision;
14 use std::cell::RefCell;
10
15
11 /// Return a Struct implementing the Graph trait
16 /// Return a Struct implementing the Graph trait
12 pub(crate) fn pyindex_to_graph(
17 pub(crate) fn pyindex_to_graph(
@@ -15,3 +20,198 b' pub(crate) fn pyindex_to_graph('
15 ) -> PyResult<cindex::Index> {
20 ) -> PyResult<cindex::Index> {
16 cindex::Index::new(py, index)
21 cindex::Index::new(py, index)
17 }
22 }
23
24 py_class!(pub class MixedIndex |py| {
25 data cindex: RefCell<cindex::Index>;
26
27 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
28 Self::create_instance(py, RefCell::new(
29 cindex::Index::new(py, cindex)?))
30 }
31
32
33 // Reforwarded C index API
34
35 // index_methods (tp_methods). Same ordering as in revlog.c
36
37 /// return the gca set of the given revs
38 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
39 self.call_cindex(py, "ancestors", args, kw)
40 }
41
42 /// return the heads of the common ancestors of the given revs
43 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
44 self.call_cindex(py, "commonancestorsheads", args, kw)
45 }
46
47 /// clear the index caches
48 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
49 self.call_cindex(py, "clearcaches", args, kw)
50 }
51
52 /// get an index entry
53 def get(&self, *args, **kw) -> PyResult<PyObject> {
54 self.call_cindex(py, "get", args, kw)
55 }
56
57 /// return `rev` associated with a node or None
58 def get_rev(&self, *args, **kw) -> PyResult<PyObject> {
59 self.call_cindex(py, "get_rev", args, kw)
60 }
61
62 /// return True if the node exist in the index
63 def has_node(&self, *args, **kw) -> PyResult<PyObject> {
64 self.call_cindex(py, "has_node", args, kw)
65 }
66
67 /// return `rev` associated with a node or raise RevlogError
68 def rev(&self, *args, **kw) -> PyResult<PyObject> {
69 self.call_cindex(py, "rev", args, kw)
70 }
71
72 /// compute phases
73 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
74 self.call_cindex(py, "computephasesmapsets", args, kw)
75 }
76
77 /// reachableroots
78 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
79 self.call_cindex(py, "reachableroots2", args, kw)
80 }
81
82 /// get head revisions
83 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
84 self.call_cindex(py, "headrevs", args, kw)
85 }
86
87 /// get filtered head revisions
88 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
89 self.call_cindex(py, "headrevsfiltered", args, kw)
90 }
91
92 /// True if the object is a snapshot
93 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
94 self.call_cindex(py, "issnapshot", args, kw)
95 }
96
97 /// Gather snapshot data in a cache dict
98 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
99 self.call_cindex(py, "findsnapshots", args, kw)
100 }
101
102 /// determine revisions with deltas to reconstruct fulltext
103 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
104 self.call_cindex(py, "deltachain", args, kw)
105 }
106
107 /// slice planned chunk read to reach a density threshold
108 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
109 self.call_cindex(py, "slicechunktodensity", args, kw)
110 }
111
112 /// append an index entry
113 def append(&self, *args, **kw) -> PyResult<PyObject> {
114 self.call_cindex(py, "append", args, kw)
115 }
116
117 /// match a potentially ambiguous node ID
118 def partialmatch(&self, *args, **kw) -> PyResult<PyObject> {
119 self.call_cindex(py, "partialmatch", args, kw)
120 }
121
122 /// find length of shortest hex nodeid of a binary ID
123 def shortest(&self, *args, **kw) -> PyResult<PyObject> {
124 self.call_cindex(py, "shortest", args, kw)
125 }
126
127 /// stats for the index
128 def stats(&self, *args, **kw) -> PyResult<PyObject> {
129 self.call_cindex(py, "stats", args, kw)
130 }
131
132 // index_sequence_methods and index_mapping_methods.
133 //
134 // Since we call back through the high level Python API,
135 // there's no point making a distinction between index_get
136 // and index_getitem.
137
138 def __len__(&self) -> PyResult<usize> {
139 self.cindex(py).borrow().inner().len(py)
140 }
141
142 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
143 // this conversion seems needless, but that's actually because
144 // `index_getitem` does not handle conversion from PyLong,
145 // which expressions such as [e for e in index] internally use.
146 // Note that we don't seem to have a direct way to call
147 // PySequence_GetItem (does the job), which would be better for
148 // for performance
149 let key = match key.extract::<Revision>(py) {
150 Ok(rev) => rev.to_py_object(py).into_object(),
151 Err(_) => key,
152 };
153 self.cindex(py).borrow().inner().get_item(py, key)
154 }
155
156 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
157 self.cindex(py).borrow().inner().set_item(py, key, value)
158 }
159
160 def __delitem__(&self, key: PyObject) -> PyResult<()> {
161 self.cindex(py).borrow().inner().del_item(py, key)
162 }
163
164 def __contains__(&self, item: PyObject) -> PyResult<bool> {
165 // ObjectProtocol does not seem to provide contains(), so
166 // this is an equivalent implementation of the index_contains()
167 // defined in revlog.c
168 let cindex = self.cindex(py).borrow();
169 match item.extract::<Revision>(py) {
170 Ok(rev) => {
171 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
172 }
173 Err(_) => {
174 cindex.inner().call_method(
175 py,
176 "has_node",
177 PyTuple::new(py, &[item]),
178 None)?
179 .extract(py)
180 }
181 }
182 }
183
184
185 });
186
187 impl MixedIndex {
188 /// forward a method call to the underlying C index
189 fn call_cindex(
190 &self,
191 py: Python,
192 name: &str,
193 args: &PyTuple,
194 kwargs: Option<&PyDict>,
195 ) -> PyResult<PyObject> {
196 self.cindex(py)
197 .borrow()
198 .inner()
199 .call_method(py, name, args, kwargs)
200 }
201 }
202
203 /// Create the module, with __package__ given from parent
204 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
205 let dotted_name = &format!("{}.revlog", package);
206 let m = PyModule::new(py, dotted_name)?;
207 m.add(py, "__package__", package)?;
208 m.add(py, "__doc__", "RevLog - Rust implementations")?;
209
210 m.add_class::<MixedIndex>(py)?;
211
212 let sys = PyModule::import(py, "sys")?;
213 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
214 sys_modules.set_item(py, dotted_name, &m)?;
215
216 Ok(m)
217 }
General Comments 0
You need to be logged in to leave comments. Login now