##// END OF EJS Templates
rust-index: moved constructor in separate impl block...
Georges Racinet -
r44990:887d0f92 default
parent child Browse files
Show More
@@ -1,235 +1,241 b''
1 // revlog.rs
1 // revlog.rs
2 //
2 //
3 // Copyright 2019 Georges Racinet <georges.racinet@octobus.net>
3 // Copyright 2019 Georges Racinet <georges.racinet@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
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::{
9 use cpython::{
10 ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, PyTuple,
10 ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, PyTuple,
11 Python, PythonObject, ToPyObject,
11 Python, PythonObject, ToPyObject,
12 };
12 };
13 use hg::Revision;
13 use hg::Revision;
14 use std::cell::RefCell;
14 use std::cell::RefCell;
15
15
16 /// Return a Struct implementing the Graph trait
16 /// Return a Struct implementing the Graph trait
17 pub(crate) fn pyindex_to_graph(
17 pub(crate) fn pyindex_to_graph(
18 py: Python,
18 py: Python,
19 index: PyObject,
19 index: PyObject,
20 ) -> PyResult<cindex::Index> {
20 ) -> PyResult<cindex::Index> {
21 match index.extract::<MixedIndex>(py) {
21 match index.extract::<MixedIndex>(py) {
22 Ok(midx) => Ok(midx.clone_cindex(py)),
22 Ok(midx) => Ok(midx.clone_cindex(py)),
23 Err(_) => cindex::Index::new(py, index),
23 Err(_) => cindex::Index::new(py, index),
24 }
24 }
25 }
25 }
26
26
27 py_class!(pub class MixedIndex |py| {
27 py_class!(pub class MixedIndex |py| {
28 data cindex: RefCell<cindex::Index>;
28 data cindex: RefCell<cindex::Index>;
29
29
30 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
30 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
31 Self::create_instance(py, RefCell::new(
31 Self::new(py, cindex)
32 cindex::Index::new(py, cindex)?))
33 }
32 }
34
33
35 /// Compatibility layer used for Python consumers needing access to the C index
34 /// Compatibility layer used for Python consumers needing access to the C index
36 ///
35 ///
37 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
36 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
38 /// that may need to build a custom `nodetree`, based on a specified revset.
37 /// that may need to build a custom `nodetree`, based on a specified revset.
39 /// With a Rust implementation of the nodemap, we will be able to get rid of
38 /// With a Rust implementation of the nodemap, we will be able to get rid of
40 /// this, by exposing our own standalone nodemap class,
39 /// this, by exposing our own standalone nodemap class,
41 /// ready to accept `MixedIndex`.
40 /// ready to accept `MixedIndex`.
42 def get_cindex(&self) -> PyResult<PyObject> {
41 def get_cindex(&self) -> PyResult<PyObject> {
43 Ok(self.cindex(py).borrow().inner().clone_ref(py))
42 Ok(self.cindex(py).borrow().inner().clone_ref(py))
44 }
43 }
45
44
46
45
47 // Reforwarded C index API
46 // Reforwarded C index API
48
47
49 // index_methods (tp_methods). Same ordering as in revlog.c
48 // index_methods (tp_methods). Same ordering as in revlog.c
50
49
51 /// return the gca set of the given revs
50 /// return the gca set of the given revs
52 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
51 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
53 self.call_cindex(py, "ancestors", args, kw)
52 self.call_cindex(py, "ancestors", args, kw)
54 }
53 }
55
54
56 /// return the heads of the common ancestors of the given revs
55 /// return the heads of the common ancestors of the given revs
57 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
56 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
58 self.call_cindex(py, "commonancestorsheads", args, kw)
57 self.call_cindex(py, "commonancestorsheads", args, kw)
59 }
58 }
60
59
61 /// clear the index caches
60 /// clear the index caches
62 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
61 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
63 self.call_cindex(py, "clearcaches", args, kw)
62 self.call_cindex(py, "clearcaches", args, kw)
64 }
63 }
65
64
66 /// get an index entry
65 /// get an index entry
67 def get(&self, *args, **kw) -> PyResult<PyObject> {
66 def get(&self, *args, **kw) -> PyResult<PyObject> {
68 self.call_cindex(py, "get", args, kw)
67 self.call_cindex(py, "get", args, kw)
69 }
68 }
70
69
71 /// return `rev` associated with a node or None
70 /// return `rev` associated with a node or None
72 def get_rev(&self, *args, **kw) -> PyResult<PyObject> {
71 def get_rev(&self, *args, **kw) -> PyResult<PyObject> {
73 self.call_cindex(py, "get_rev", args, kw)
72 self.call_cindex(py, "get_rev", args, kw)
74 }
73 }
75
74
76 /// return True if the node exist in the index
75 /// return True if the node exist in the index
77 def has_node(&self, *args, **kw) -> PyResult<PyObject> {
76 def has_node(&self, *args, **kw) -> PyResult<PyObject> {
78 self.call_cindex(py, "has_node", args, kw)
77 self.call_cindex(py, "has_node", args, kw)
79 }
78 }
80
79
81 /// return `rev` associated with a node or raise RevlogError
80 /// return `rev` associated with a node or raise RevlogError
82 def rev(&self, *args, **kw) -> PyResult<PyObject> {
81 def rev(&self, *args, **kw) -> PyResult<PyObject> {
83 self.call_cindex(py, "rev", args, kw)
82 self.call_cindex(py, "rev", args, kw)
84 }
83 }
85
84
86 /// compute phases
85 /// compute phases
87 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
86 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
88 self.call_cindex(py, "computephasesmapsets", args, kw)
87 self.call_cindex(py, "computephasesmapsets", args, kw)
89 }
88 }
90
89
91 /// reachableroots
90 /// reachableroots
92 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
91 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
93 self.call_cindex(py, "reachableroots2", args, kw)
92 self.call_cindex(py, "reachableroots2", args, kw)
94 }
93 }
95
94
96 /// get head revisions
95 /// get head revisions
97 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
96 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
98 self.call_cindex(py, "headrevs", args, kw)
97 self.call_cindex(py, "headrevs", args, kw)
99 }
98 }
100
99
101 /// get filtered head revisions
100 /// get filtered head revisions
102 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
101 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
103 self.call_cindex(py, "headrevsfiltered", args, kw)
102 self.call_cindex(py, "headrevsfiltered", args, kw)
104 }
103 }
105
104
106 /// True if the object is a snapshot
105 /// True if the object is a snapshot
107 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
106 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
108 self.call_cindex(py, "issnapshot", args, kw)
107 self.call_cindex(py, "issnapshot", args, kw)
109 }
108 }
110
109
111 /// Gather snapshot data in a cache dict
110 /// Gather snapshot data in a cache dict
112 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
111 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
113 self.call_cindex(py, "findsnapshots", args, kw)
112 self.call_cindex(py, "findsnapshots", args, kw)
114 }
113 }
115
114
116 /// determine revisions with deltas to reconstruct fulltext
115 /// determine revisions with deltas to reconstruct fulltext
117 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
116 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
118 self.call_cindex(py, "deltachain", args, kw)
117 self.call_cindex(py, "deltachain", args, kw)
119 }
118 }
120
119
121 /// slice planned chunk read to reach a density threshold
120 /// slice planned chunk read to reach a density threshold
122 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
121 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
123 self.call_cindex(py, "slicechunktodensity", args, kw)
122 self.call_cindex(py, "slicechunktodensity", args, kw)
124 }
123 }
125
124
126 /// append an index entry
125 /// append an index entry
127 def append(&self, *args, **kw) -> PyResult<PyObject> {
126 def append(&self, *args, **kw) -> PyResult<PyObject> {
128 self.call_cindex(py, "append", args, kw)
127 self.call_cindex(py, "append", args, kw)
129 }
128 }
130
129
131 /// match a potentially ambiguous node ID
130 /// match a potentially ambiguous node ID
132 def partialmatch(&self, *args, **kw) -> PyResult<PyObject> {
131 def partialmatch(&self, *args, **kw) -> PyResult<PyObject> {
133 self.call_cindex(py, "partialmatch", args, kw)
132 self.call_cindex(py, "partialmatch", args, kw)
134 }
133 }
135
134
136 /// find length of shortest hex nodeid of a binary ID
135 /// find length of shortest hex nodeid of a binary ID
137 def shortest(&self, *args, **kw) -> PyResult<PyObject> {
136 def shortest(&self, *args, **kw) -> PyResult<PyObject> {
138 self.call_cindex(py, "shortest", args, kw)
137 self.call_cindex(py, "shortest", args, kw)
139 }
138 }
140
139
141 /// stats for the index
140 /// stats for the index
142 def stats(&self, *args, **kw) -> PyResult<PyObject> {
141 def stats(&self, *args, **kw) -> PyResult<PyObject> {
143 self.call_cindex(py, "stats", args, kw)
142 self.call_cindex(py, "stats", args, kw)
144 }
143 }
145
144
146 // index_sequence_methods and index_mapping_methods.
145 // index_sequence_methods and index_mapping_methods.
147 //
146 //
148 // Since we call back through the high level Python API,
147 // Since we call back through the high level Python API,
149 // there's no point making a distinction between index_get
148 // there's no point making a distinction between index_get
150 // and index_getitem.
149 // and index_getitem.
151
150
152 def __len__(&self) -> PyResult<usize> {
151 def __len__(&self) -> PyResult<usize> {
153 self.cindex(py).borrow().inner().len(py)
152 self.cindex(py).borrow().inner().len(py)
154 }
153 }
155
154
156 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
155 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
157 // this conversion seems needless, but that's actually because
156 // this conversion seems needless, but that's actually because
158 // `index_getitem` does not handle conversion from PyLong,
157 // `index_getitem` does not handle conversion from PyLong,
159 // which expressions such as [e for e in index] internally use.
158 // which expressions such as [e for e in index] internally use.
160 // Note that we don't seem to have a direct way to call
159 // Note that we don't seem to have a direct way to call
161 // PySequence_GetItem (does the job), which would be better for
160 // PySequence_GetItem (does the job), which would be better for
162 // for performance
161 // for performance
163 let key = match key.extract::<Revision>(py) {
162 let key = match key.extract::<Revision>(py) {
164 Ok(rev) => rev.to_py_object(py).into_object(),
163 Ok(rev) => rev.to_py_object(py).into_object(),
165 Err(_) => key,
164 Err(_) => key,
166 };
165 };
167 self.cindex(py).borrow().inner().get_item(py, key)
166 self.cindex(py).borrow().inner().get_item(py, key)
168 }
167 }
169
168
170 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
169 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
171 self.cindex(py).borrow().inner().set_item(py, key, value)
170 self.cindex(py).borrow().inner().set_item(py, key, value)
172 }
171 }
173
172
174 def __delitem__(&self, key: PyObject) -> PyResult<()> {
173 def __delitem__(&self, key: PyObject) -> PyResult<()> {
175 self.cindex(py).borrow().inner().del_item(py, key)
174 self.cindex(py).borrow().inner().del_item(py, key)
176 }
175 }
177
176
178 def __contains__(&self, item: PyObject) -> PyResult<bool> {
177 def __contains__(&self, item: PyObject) -> PyResult<bool> {
179 // ObjectProtocol does not seem to provide contains(), so
178 // ObjectProtocol does not seem to provide contains(), so
180 // this is an equivalent implementation of the index_contains()
179 // this is an equivalent implementation of the index_contains()
181 // defined in revlog.c
180 // defined in revlog.c
182 let cindex = self.cindex(py).borrow();
181 let cindex = self.cindex(py).borrow();
183 match item.extract::<Revision>(py) {
182 match item.extract::<Revision>(py) {
184 Ok(rev) => {
183 Ok(rev) => {
185 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
184 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
186 }
185 }
187 Err(_) => {
186 Err(_) => {
188 cindex.inner().call_method(
187 cindex.inner().call_method(
189 py,
188 py,
190 "has_node",
189 "has_node",
191 PyTuple::new(py, &[item]),
190 PyTuple::new(py, &[item]),
192 None)?
191 None)?
193 .extract(py)
192 .extract(py)
194 }
193 }
195 }
194 }
196 }
195 }
197
196
198
197
199 });
198 });
200
199
201 impl MixedIndex {
200 impl MixedIndex {
201 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
202 Self::create_instance(
203 py,
204 RefCell::new(cindex::Index::new(py, cindex)?),
205 )
206 }
207
202 /// forward a method call to the underlying C index
208 /// forward a method call to the underlying C index
203 fn call_cindex(
209 fn call_cindex(
204 &self,
210 &self,
205 py: Python,
211 py: Python,
206 name: &str,
212 name: &str,
207 args: &PyTuple,
213 args: &PyTuple,
208 kwargs: Option<&PyDict>,
214 kwargs: Option<&PyDict>,
209 ) -> PyResult<PyObject> {
215 ) -> PyResult<PyObject> {
210 self.cindex(py)
216 self.cindex(py)
211 .borrow()
217 .borrow()
212 .inner()
218 .inner()
213 .call_method(py, name, args, kwargs)
219 .call_method(py, name, args, kwargs)
214 }
220 }
215
221
216 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
222 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
217 self.cindex(py).borrow().clone_ref(py)
223 self.cindex(py).borrow().clone_ref(py)
218 }
224 }
219 }
225 }
220
226
221 /// Create the module, with __package__ given from parent
227 /// Create the module, with __package__ given from parent
222 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
228 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
223 let dotted_name = &format!("{}.revlog", package);
229 let dotted_name = &format!("{}.revlog", package);
224 let m = PyModule::new(py, dotted_name)?;
230 let m = PyModule::new(py, dotted_name)?;
225 m.add(py, "__package__", package)?;
231 m.add(py, "__package__", package)?;
226 m.add(py, "__doc__", "RevLog - Rust implementations")?;
232 m.add(py, "__doc__", "RevLog - Rust implementations")?;
227
233
228 m.add_class::<MixedIndex>(py)?;
234 m.add_class::<MixedIndex>(py)?;
229
235
230 let sys = PyModule::import(py, "sys")?;
236 let sys = PyModule::import(py, "sys")?;
231 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
237 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
232 sys_modules.set_item(py, dotted_name, &m)?;
238 sys_modules.set_item(py, dotted_name, &m)?;
233
239
234 Ok(m)
240 Ok(m)
235 }
241 }
General Comments 0
You need to be logged in to leave comments. Login now