##// END OF EJS Templates
rust-dirstate: add "dirs" rust-cpython binding...
Raphaël Gomès -
r42737:ce94f962 default
parent child Browse files
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, PyResult,
14 exc, ObjectProtocol, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject,
15 PySequence, PythonObject, PyTuple, Python, ToPyObject,
15 PyResult, PySequence, PyTuple, Python, PythonObject, ToPyObject,
16 };
16 };
17 use hg::{
17 use hg::{
18 pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry,
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 pack_dirstate_wrapper(
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, mode, size, mtime,
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