Show More
@@ -0,0 +1,110 b'' | |||
|
1 | // dirs_multiset.rs | |
|
2 | // | |
|
3 | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |
|
4 | // | |
|
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. | |
|
7 | ||
|
8 | //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the | |
|
9 | //! `hg-core` package. | |
|
10 | ||
|
11 | use std::cell::RefCell; | |
|
12 | ||
|
13 | use cpython::{ | |
|
14 | exc, ObjectProtocol, PyBytes, PyDict, PyErr, PyObject, PyResult, | |
|
15 | ToPyObject, | |
|
16 | }; | |
|
17 | ||
|
18 | use crate::dirstate::extract_dirstate_vec; | |
|
19 | use hg::{DirsIterable, DirsMultiset, DirstateMapError}; | |
|
20 | ||
|
21 | py_class!(pub class Dirs |py| { | |
|
22 | data dirs_map: RefCell<DirsMultiset>; | |
|
23 | ||
|
24 | // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes | |
|
25 | // a `list`) | |
|
26 | def __new__( | |
|
27 | _cls, | |
|
28 | map: PyObject, | |
|
29 | skip: Option<PyObject> = None | |
|
30 | ) -> PyResult<Self> { | |
|
31 | let mut skip_state: Option<i8> = None; | |
|
32 | if let Some(skip) = skip { | |
|
33 | skip_state = Some(skip.extract::<PyBytes>(py)?.data(py)[0] as i8); | |
|
34 | } | |
|
35 | let dirs_map; | |
|
36 | ||
|
37 | if let Ok(map) = map.cast_as::<PyDict>(py) { | |
|
38 | let dirstate_vec = extract_dirstate_vec(py, &map)?; | |
|
39 | dirs_map = DirsMultiset::new( | |
|
40 | DirsIterable::Dirstate(dirstate_vec), | |
|
41 | skip_state, | |
|
42 | ) | |
|
43 | } else { | |
|
44 | let map: Result<Vec<Vec<u8>>, PyErr> = map | |
|
45 | .iter(py)? | |
|
46 | .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned())) | |
|
47 | .collect(); | |
|
48 | dirs_map = DirsMultiset::new( | |
|
49 | DirsIterable::Manifest(map?), | |
|
50 | skip_state, | |
|
51 | ) | |
|
52 | } | |
|
53 | ||
|
54 | Self::create_instance(py, RefCell::new(dirs_map)) | |
|
55 | } | |
|
56 | ||
|
57 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { | |
|
58 | self.dirs_map(py).borrow_mut().add_path( | |
|
59 | path.extract::<PyBytes>(py)?.data(py), | |
|
60 | ); | |
|
61 | Ok(py.None()) | |
|
62 | } | |
|
63 | ||
|
64 | def delpath(&self, path: PyObject) -> PyResult<PyObject> { | |
|
65 | self.dirs_map(py).borrow_mut().delete_path( | |
|
66 | path.extract::<PyBytes>(py)?.data(py), | |
|
67 | ) | |
|
68 | .and(Ok(py.None())) | |
|
69 | .or_else(|e| { | |
|
70 | match e { | |
|
71 | DirstateMapError::PathNotFound(_p) => { | |
|
72 | Err(PyErr::new::<exc::ValueError, _>( | |
|
73 | py, | |
|
74 | "expected a value, found none".to_string(), | |
|
75 | )) | |
|
76 | } | |
|
77 | DirstateMapError::EmptyPath => { | |
|
78 | Ok(py.None()) | |
|
79 | } | |
|
80 | } | |
|
81 | }) | |
|
82 | } | |
|
83 | ||
|
84 | // This is really inefficient on top of being ugly, but it's an easy way | |
|
85 | // of having it work to continue working on the rest of the module | |
|
86 | // hopefully bypassing Python entirely pretty soon. | |
|
87 | def __iter__(&self) -> PyResult<PyObject> { | |
|
88 | let dict = PyDict::new(py); | |
|
89 | ||
|
90 | for (key, value) in self.dirs_map(py).borrow().iter() { | |
|
91 | dict.set_item( | |
|
92 | py, | |
|
93 | PyBytes::new(py, &key[..]), | |
|
94 | value.to_py_object(py), | |
|
95 | )?; | |
|
96 | } | |
|
97 | ||
|
98 | let locals = PyDict::new(py); | |
|
99 | locals.set_item(py, "obj", dict)?; | |
|
100 | ||
|
101 | py.eval("iter(obj)", None, Some(&locals)) | |
|
102 | } | |
|
103 | ||
|
104 | def __contains__(&self, item: PyObject) -> PyResult<bool> { | |
|
105 | Ok(self | |
|
106 | .dirs_map(py) | |
|
107 | .borrow() | |
|
108 | .contains_key(item.extract::<PyBytes>(py)?.data(py).as_ref())) | |
|
109 | } | |
|
110 | }); |
@@ -9,22 +9,21 b'' | |||
|
9 | 9 | //! `hg-core` package. |
|
10 | 10 | //! |
|
11 | 11 | //! From Python, this will be seen as `mercurial.rustext.dirstate` |
|
12 | ||
|
12 | mod dirs_multiset; | |
|
13 | use crate::dirstate::dirs_multiset::Dirs; | |
|
13 | 14 | use cpython::{ |
|
14 |
exc |
|
|
15 |
|
|
|
15 | exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject, PyResult, | |
|
16 | PySequence, PyTuple, Python, PythonObject, ToPyObject, | |
|
16 | 17 | }; |
|
17 | 18 | use hg::{ |
|
18 |
pack_dirstate, parse_dirstate, CopyVecEntry, Dirs |
|
|
19 | DirstateEntry, DirstateMapError, DirstatePackError, DirstateParents, | |
|
20 | DirstateParseError, DirstateVec, | |
|
19 | pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry, | |
|
20 | DirstatePackError, DirstateParents, DirstateParseError, DirstateVec, | |
|
21 | 21 | }; |
|
22 | 22 | use libc::{c_char, c_int}; |
|
23 | 23 | #[cfg(feature = "python27")] |
|
24 | 24 | use python27_sys::PyCapsule_Import; |
|
25 | 25 | #[cfg(feature = "python3")] |
|
26 | 26 | use python3_sys::PyCapsule_Import; |
|
27 | use std::cell::RefCell; | |
|
28 | 27 | use std::collections::HashMap; |
|
29 | 28 | use std::ffi::CStr; |
|
30 | 29 | use std::mem::transmute; |
@@ -201,97 +200,6 b' fn pack_dirstate_wrapper(' | |||
|
201 | 200 | } |
|
202 | 201 | } |
|
203 | 202 | |
|
204 | py_class!(pub class Dirs |py| { | |
|
205 | data dirs_map: RefCell<DirsMultiset>; | |
|
206 | ||
|
207 | // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes | |
|
208 | // a `list`) | |
|
209 | def __new__( | |
|
210 | _cls, | |
|
211 | map: PyObject, | |
|
212 | skip: Option<PyObject> = None | |
|
213 | ) -> PyResult<Self> { | |
|
214 | let mut skip_state: Option<i8> = None; | |
|
215 | if let Some(skip) = skip { | |
|
216 | skip_state = Some(skip.extract::<PyBytes>(py)?.data(py)[0] as i8); | |
|
217 | } | |
|
218 | let dirs_map; | |
|
219 | ||
|
220 | if let Ok(map) = map.cast_as::<PyDict>(py) { | |
|
221 | let dirstate_vec = extract_dirstate_vec(py, &map)?; | |
|
222 | dirs_map = DirsMultiset::new( | |
|
223 | DirsIterable::Dirstate(dirstate_vec), | |
|
224 | skip_state, | |
|
225 | ) | |
|
226 | } else { | |
|
227 | let map: Result<Vec<Vec<u8>>, PyErr> = map | |
|
228 | .iter(py)? | |
|
229 | .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned())) | |
|
230 | .collect(); | |
|
231 | dirs_map = DirsMultiset::new( | |
|
232 | DirsIterable::Manifest(map?), | |
|
233 | skip_state, | |
|
234 | ) | |
|
235 | } | |
|
236 | ||
|
237 | Self::create_instance(py, RefCell::new(dirs_map)) | |
|
238 | } | |
|
239 | ||
|
240 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { | |
|
241 | self.dirs_map(py).borrow_mut().add_path( | |
|
242 | path.extract::<PyBytes>(py)?.data(py), | |
|
243 | ); | |
|
244 | Ok(py.None()) | |
|
245 | } | |
|
246 | ||
|
247 | def delpath(&self, path: PyObject) -> PyResult<PyObject> { | |
|
248 | self.dirs_map(py).borrow_mut().delete_path( | |
|
249 | path.extract::<PyBytes>(py)?.data(py), | |
|
250 | ) | |
|
251 | .and(Ok(py.None())) | |
|
252 | .or_else(|e| { | |
|
253 | match e { | |
|
254 | DirstateMapError::PathNotFound(_p) => { | |
|
255 | Err(PyErr::new::<exc::ValueError, _>( | |
|
256 | py, | |
|
257 | "expected a value, found none".to_string(), | |
|
258 | )) | |
|
259 | } | |
|
260 | DirstateMapError::EmptyPath => { | |
|
261 | Ok(py.None()) | |
|
262 | } | |
|
263 | } | |
|
264 | }) | |
|
265 | } | |
|
266 | ||
|
267 | // This is really inefficient on top of being ugly, but it's an easy way | |
|
268 | // of having it work to continue working on the rest of the module | |
|
269 | // hopefully bypassing Python entirely pretty soon. | |
|
270 | def __iter__(&self) -> PyResult<PyObject> { | |
|
271 | let dict = PyDict::new(py); | |
|
272 | ||
|
273 | for (key, value) in self.dirs_map(py).borrow().iter() { | |
|
274 | dict.set_item( | |
|
275 | py, | |
|
276 | PyBytes::new(py, &key[..]), | |
|
277 | value.to_py_object(py), | |
|
278 | )?; | |
|
279 | } | |
|
280 | ||
|
281 | let locals = PyDict::new(py); | |
|
282 | locals.set_item(py, "obj", dict)?; | |
|
283 | ||
|
284 | py.eval("iter(obj)", None, Some(&locals)) | |
|
285 | } | |
|
286 | ||
|
287 | def __contains__(&self, item: PyObject) -> PyResult<bool> { | |
|
288 | Ok(self | |
|
289 | .dirs_map(py) | |
|
290 | .borrow() | |
|
291 | .contains_key(item.extract::<PyBytes>(py)?.data(py).as_ref())) | |
|
292 | } | |
|
293 | }); | |
|
294 | ||
|
295 | 203 | /// Create the module, with `__package__` given from parent |
|
296 | 204 | pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { |
|
297 | 205 | let dotted_name = &format!("{}.dirstate", package); |
General Comments 0
You need to be logged in to leave comments.
Login now