Show More
@@ -11,21 +11,25 b'' | |||||
11 | //! From Python, this will be seen as `mercurial.rustext.dirstate` |
|
11 | //! From Python, this will be seen as `mercurial.rustext.dirstate` | |
12 |
|
12 | |||
13 | use cpython::{ |
|
13 | use cpython::{ | |
14 |
exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject, |
|
14 | exc, ObjectProtocol, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject, | |
15 |
Py |
|
15 | PyResult, PySequence, PyTuple, Python, PythonObject, ToPyObject, | |
16 | }; |
|
16 | }; | |
17 | use hg::{ |
|
17 | use hg::{ | |
18 |
pack_dirstate, parse_dirstate, CopyVecEntry, Dirstate |
|
18 | pack_dirstate, parse_dirstate, CopyVecEntry, DirsIterable, DirsMultiset, | |
19 | DirstatePackError, DirstateParents, DirstateParseError, DirstateVec, |
|
19 | DirstateEntry, DirstateMapError, DirstatePackError, DirstateParents, | |
|
20 | DirstateParseError, DirstateVec, | |||
20 | }; |
|
21 | }; | |
21 | use std::collections::HashMap; |
|
22 | use std::collections::HashMap; | |
22 | use std::ffi::CStr; |
|
23 | use std::ffi::CStr; | |
|
24 | ||||
23 | #[cfg(feature = "python27")] |
|
25 | #[cfg(feature = "python27")] | |
24 | extern crate python27_sys as python_sys; |
|
26 | extern crate python27_sys as python_sys; | |
25 | #[cfg(feature = "python3")] |
|
27 | #[cfg(feature = "python3")] | |
26 | extern crate python3_sys as python_sys; |
|
28 | extern crate python3_sys as python_sys; | |
|
29 | ||||
27 | use self::python_sys::PyCapsule_Import; |
|
30 | use self::python_sys::PyCapsule_Import; | |
28 | use libc::{c_char, c_int}; |
|
31 | use libc::{c_char, c_int}; | |
|
32 | use std::cell::RefCell; | |||
29 | use std::mem::transmute; |
|
33 | use std::mem::transmute; | |
30 |
|
34 | |||
31 | /// C code uses a custom `dirstate_tuple` type, checks in multiple instances |
|
35 | /// C code uses a custom `dirstate_tuple` type, checks in multiple instances | |
@@ -102,20 +106,11 b' fn parse_dirstate_wrapper(' | |||||
102 | } |
|
106 | } | |
103 | } |
|
107 | } | |
104 |
|
108 | |||
105 |
fn |
|
109 | fn extract_dirstate_vec( | |
106 | py: Python, |
|
110 | py: Python, | |
107 | dmap: PyDict, |
|
111 | dmap: &PyDict, | |
108 | copymap: PyDict, |
|
112 | ) -> Result<DirstateVec, PyErr> { | |
109 | pl: PyTuple, |
|
113 | dmap.items(py) | |
110 | now: PyInt, |
|
|||
111 | ) -> PyResult<PyBytes> { |
|
|||
112 | let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?; |
|
|||
113 | let p1: &[u8] = p1.data(py); |
|
|||
114 | let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; |
|
|||
115 | let p2: &[u8] = p2.data(py); |
|
|||
116 |
|
||||
117 | let dirstate_vec: Result<DirstateVec, PyErr> = dmap |
|
|||
118 | .items(py) |
|
|||
119 | .iter() |
|
114 | .iter() | |
120 | .map(|(filename, stats)| { |
|
115 | .map(|(filename, stats)| { | |
121 | let stats = stats.extract::<PySequence>(py)?; |
|
116 | let stats = stats.extract::<PySequence>(py)?; | |
@@ -136,7 +131,22 b' fn pack_dirstate_wrapper(' | |||||
136 | }, |
|
131 | }, | |
137 | )) |
|
132 | )) | |
138 | }) |
|
133 | }) | |
139 |
.collect() |
|
134 | .collect() | |
|
135 | } | |||
|
136 | ||||
|
137 | fn pack_dirstate_wrapper( | |||
|
138 | py: Python, | |||
|
139 | dmap: PyDict, | |||
|
140 | copymap: PyDict, | |||
|
141 | pl: PyTuple, | |||
|
142 | now: PyInt, | |||
|
143 | ) -> PyResult<PyBytes> { | |||
|
144 | let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?; | |||
|
145 | let p1: &[u8] = p1.data(py); | |||
|
146 | let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; | |||
|
147 | let p2: &[u8] = p2.data(py); | |||
|
148 | ||||
|
149 | let dirstate_vec = extract_dirstate_vec(py, &dmap)?; | |||
140 |
|
150 | |||
141 | let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap |
|
151 | let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap | |
142 | .items(py) |
|
152 | .items(py) | |
@@ -150,7 +160,7 b' fn pack_dirstate_wrapper(' | |||||
150 | .collect(); |
|
160 | .collect(); | |
151 |
|
161 | |||
152 | match pack_dirstate( |
|
162 | match pack_dirstate( | |
153 |
&dirstate_vec |
|
163 | &dirstate_vec, | |
154 | &copies?, |
|
164 | &copies?, | |
155 | DirstateParents { p1, p2 }, |
|
165 | DirstateParents { p1, p2 }, | |
156 | now.as_object().extract::<i32>(py)?, |
|
166 | now.as_object().extract::<i32>(py)?, | |
@@ -170,7 +180,10 b' fn pack_dirstate_wrapper(' | |||||
170 | py, |
|
180 | py, | |
171 | PyBytes::new(py, &filename[..]), |
|
181 | PyBytes::new(py, &filename[..]), | |
172 | decapsule_make_dirstate_tuple(py)?( |
|
182 | decapsule_make_dirstate_tuple(py)?( | |
173 |
state as c_char, |
|
183 | state as c_char, | |
|
184 | mode, | |||
|
185 | size, | |||
|
186 | mtime, | |||
174 | ), |
|
187 | ), | |
175 | )?; |
|
188 | )?; | |
176 | } |
|
189 | } | |
@@ -191,10 +204,103 b' fn pack_dirstate_wrapper(' | |||||
191 | } |
|
204 | } | |
192 | } |
|
205 | } | |
193 |
|
206 | |||
|
207 | py_class!(pub class Dirs |py| { | |||
|
208 | data dirs_map: RefCell<DirsMultiset>; | |||
|
209 | ||||
|
210 | // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes | |||
|
211 | // a `list`) | |||
|
212 | def __new__( | |||
|
213 | _cls, | |||
|
214 | map: PyObject, | |||
|
215 | skip: Option<PyObject> = None | |||
|
216 | ) -> PyResult<Self> { | |||
|
217 | let mut skip_state: Option<i8> = None; | |||
|
218 | if let Some(skip) = skip { | |||
|
219 | skip_state = Some(skip.extract::<PyBytes>(py)?.data(py)[0] as i8); | |||
|
220 | } | |||
|
221 | let dirs_map; | |||
|
222 | ||||
|
223 | if let Ok(map) = map.cast_as::<PyDict>(py) { | |||
|
224 | let dirstate_vec = extract_dirstate_vec(py, &map)?; | |||
|
225 | dirs_map = DirsMultiset::new( | |||
|
226 | DirsIterable::Dirstate(dirstate_vec), | |||
|
227 | skip_state, | |||
|
228 | ) | |||
|
229 | } else { | |||
|
230 | let map: Result<Vec<Vec<u8>>, PyErr> = map | |||
|
231 | .iter(py)? | |||
|
232 | .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned())) | |||
|
233 | .collect(); | |||
|
234 | dirs_map = DirsMultiset::new( | |||
|
235 | DirsIterable::Manifest(map?), | |||
|
236 | skip_state, | |||
|
237 | ) | |||
|
238 | } | |||
|
239 | ||||
|
240 | Self::create_instance(py, RefCell::new(dirs_map)) | |||
|
241 | } | |||
|
242 | ||||
|
243 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { | |||
|
244 | self.dirs_map(py).borrow_mut().add_path( | |||
|
245 | path.extract::<PyBytes>(py)?.data(py), | |||
|
246 | ); | |||
|
247 | Ok(py.None()) | |||
|
248 | } | |||
|
249 | ||||
|
250 | def delpath(&self, path: PyObject) -> PyResult<PyObject> { | |||
|
251 | self.dirs_map(py).borrow_mut().delete_path( | |||
|
252 | path.extract::<PyBytes>(py)?.data(py), | |||
|
253 | ) | |||
|
254 | .and(Ok(py.None())) | |||
|
255 | .or_else(|e| { | |||
|
256 | match e { | |||
|
257 | DirstateMapError::PathNotFound(_p) => { | |||
|
258 | Err(PyErr::new::<exc::ValueError, _>( | |||
|
259 | py, | |||
|
260 | "expected a value, found none".to_string(), | |||
|
261 | )) | |||
|
262 | } | |||
|
263 | DirstateMapError::EmptyPath => { | |||
|
264 | Ok(py.None()) | |||
|
265 | } | |||
|
266 | } | |||
|
267 | }) | |||
|
268 | } | |||
|
269 | ||||
|
270 | // This is really inefficient on top of being ugly, but it's an easy way | |||
|
271 | // of having it work to continue working on the rest of the module | |||
|
272 | // hopefully bypassing Python entirely pretty soon. | |||
|
273 | def __iter__(&self) -> PyResult<PyObject> { | |||
|
274 | let dict = PyDict::new(py); | |||
|
275 | ||||
|
276 | for (key, value) in self.dirs_map(py).borrow().iter() { | |||
|
277 | dict.set_item( | |||
|
278 | py, | |||
|
279 | PyBytes::new(py, &key[..]), | |||
|
280 | value.to_py_object(py), | |||
|
281 | )?; | |||
|
282 | } | |||
|
283 | ||||
|
284 | let locals = PyDict::new(py); | |||
|
285 | locals.set_item(py, "obj", dict)?; | |||
|
286 | ||||
|
287 | py.eval("iter(obj)", None, Some(&locals)) | |||
|
288 | } | |||
|
289 | ||||
|
290 | def __contains__(&self, item: PyObject) -> PyResult<bool> { | |||
|
291 | Ok(self | |||
|
292 | .dirs_map(py) | |||
|
293 | .borrow() | |||
|
294 | .get(&item.extract::<PyBytes>(py)?.data(py).to_owned()) | |||
|
295 | .is_some()) | |||
|
296 | } | |||
|
297 | }); | |||
|
298 | ||||
194 | /// Create the module, with `__package__` given from parent |
|
299 | /// Create the module, with `__package__` given from parent | |
195 | pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { |
|
300 | pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | |
196 | let dotted_name = &format!("{}.dirstate", package); |
|
301 | let dotted_name = &format!("{}.dirstate", package); | |
197 | let m = PyModule::new(py, dotted_name)?; |
|
302 | let m = PyModule::new(py, dotted_name)?; | |
|
303 | ||||
198 | m.add(py, "__package__", package)?; |
|
304 | m.add(py, "__package__", package)?; | |
199 | m.add(py, "__doc__", "Dirstate - Rust implementation")?; |
|
305 | m.add(py, "__doc__", "Dirstate - Rust implementation")?; | |
200 | m.add( |
|
306 | m.add( | |
@@ -219,6 +325,8 b' pub fn init_module(py: Python, package: ' | |||||
219 | ), |
|
325 | ), | |
220 | )?; |
|
326 | )?; | |
221 |
|
327 | |||
|
328 | m.add_class::<Dirs>(py)?; | |||
|
329 | ||||
222 | let sys = PyModule::import(py, "sys")?; |
|
330 | let sys = PyModule::import(py, "sys")?; | |
223 | let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; |
|
331 | let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | |
224 | sys_modules.set_item(py, dotted_name, &m)?; |
|
332 | sys_modules.set_item(py, dotted_name, &m)?; |
General Comments 0
You need to be logged in to leave comments.
Login now