##// END OF EJS Templates
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
Raphaël Gomès -
r43567:478d0b1b default
parent child Browse files
Show More
@@ -0,0 +1,82 b''
1 // status.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::status` module provided by the
9 //! `hg-core` crate. From Python, this will be seen as `rustext.dirstate.status`.
10 //!
11
12 use crate::dirstate::DirstateMap;
13 use cpython::exc::ValueError;
14 use cpython::{
15 PyBytes, PyErr, PyList, PyObject, PyResult, Python, PythonObject,
16 ToPyObject,
17 };
18 use hg::utils::files::get_path_from_bytes;
19
20 use hg::utils::hg_path::HgPath;
21 use hg::{status, utils::hg_path::HgPathBuf};
22
23 /// This will be useless once trait impls for collection are added to `PyBytes`
24 /// upstream.
25 fn collect_pybytes_list<P: AsRef<HgPath>>(
26 py: Python,
27 collection: &[P],
28 ) -> PyList {
29 let list = PyList::new(py, &[]);
30
31 for (i, path) in collection.iter().enumerate() {
32 list.insert_item(
33 py,
34 i,
35 PyBytes::new(py, path.as_ref().as_bytes()).into_object(),
36 )
37 }
38
39 list
40 }
41
42 pub fn status_wrapper(
43 py: Python,
44 dmap: DirstateMap,
45 root_dir: PyObject,
46 files: PyList,
47 list_clean: bool,
48 last_normal_time: i64,
49 check_exec: bool,
50 ) -> PyResult<(PyList, PyList, PyList, PyList, PyList, PyList, PyList)> {
51 let bytes = root_dir.extract::<PyBytes>(py)?;
52 let root_dir = get_path_from_bytes(bytes.data(py));
53
54 let dmap: DirstateMap = dmap.to_py_object(py);
55 let dmap = dmap.get_inner(py);
56
57 let files: PyResult<Vec<HgPathBuf>> = files
58 .iter(py)
59 .map(|f| Ok(HgPathBuf::from_bytes(f.extract::<PyBytes>(py)?.data(py))))
60 .collect();
61 let files = files?;
62
63 let (lookup, status_res) = status(
64 &dmap,
65 &root_dir,
66 &files,
67 list_clean,
68 last_normal_time,
69 check_exec,
70 )
71 .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
72
73 let modified = collect_pybytes_list(py, status_res.modified.as_ref());
74 let added = collect_pybytes_list(py, status_res.added.as_ref());
75 let removed = collect_pybytes_list(py, status_res.removed.as_ref());
76 let deleted = collect_pybytes_list(py, status_res.deleted.as_ref());
77 let clean = collect_pybytes_list(py, status_res.clean.as_ref());
78 let lookup = collect_pybytes_list(py, lookup.as_ref());
79 let unknown = PyList::new(py, &[]);
80
81 Ok((lookup, modified, added, removed, deleted, unknown, clean))
82 }
@@ -1,114 +1,132 b''
1 1 // dirstate.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 //! Bindings for the `hg::dirstate` module provided by the
9 9 //! `hg-core` package.
10 10 //!
11 11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
12 12 mod copymap;
13 13 mod dirs_multiset;
14 14 mod dirstate_map;
15 use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap};
15 mod status;
16 use crate::dirstate::{
17 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
18 };
16 19 use cpython::{
17 exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence,
18 Python,
20 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
21 PySequence, Python,
19 22 };
20 23 use hg::{
21 24 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
22 25 StateMap,
23 26 };
24 27 use libc::{c_char, c_int};
25 28 use std::convert::TryFrom;
26 29
27 30 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
28 31 // for this type, and raises a Python `Exception` if the check does not pass.
29 32 // Because this type differs only in name from the regular Python tuple, it
30 33 // would be a good idea in the near future to remove it entirely to allow
31 34 // for a pure Python tuple of the same effective structure to be used,
32 35 // rendering this type and the capsule below useless.
33 36 py_capsule_fn!(
34 37 from mercurial.cext.parsers import make_dirstate_tuple_CAPI
35 38 as make_dirstate_tuple_capi
36 39 signature (
37 40 state: c_char,
38 41 mode: c_int,
39 42 size: c_int,
40 43 mtime: c_int,
41 44 ) -> *mut RawPyObject
42 45 );
43 46
44 47 pub fn make_dirstate_tuple(
45 48 py: Python,
46 49 entry: &DirstateEntry,
47 50 ) -> PyResult<PyObject> {
48 51 // might be silly to retrieve capsule function in hot loop
49 52 let make = make_dirstate_tuple_capi::retrieve(py)?;
50 53
51 54 let &DirstateEntry {
52 55 state,
53 56 mode,
54 57 size,
55 58 mtime,
56 59 } = entry;
57 60 // Explicitly go through u8 first, then cast to platform-specific `c_char`
58 61 // because Into<u8> has a specific implementation while `as c_char` would
59 62 // just do a naive enum cast.
60 63 let state_code: u8 = state.into();
61 64
62 65 let maybe_obj = unsafe {
63 66 let ptr = make(state_code as c_char, mode, size, mtime);
64 67 PyObject::from_owned_ptr_opt(py, ptr)
65 68 };
66 69 maybe_obj.ok_or_else(|| PyErr::fetch(py))
67 70 }
68 71
69 72 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
70 73 dmap.items(py)
71 74 .iter()
72 75 .map(|(filename, stats)| {
73 76 let stats = stats.extract::<PySequence>(py)?;
74 77 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
75 78 let state = EntryState::try_from(state.data(py)[0]).map_err(
76 79 |e: DirstateParseError| {
77 80 PyErr::new::<exc::ValueError, _>(py, e.to_string())
78 81 },
79 82 )?;
80 83 let mode = stats.get_item(py, 1)?.extract(py)?;
81 84 let size = stats.get_item(py, 2)?.extract(py)?;
82 85 let mtime = stats.get_item(py, 3)?.extract(py)?;
83 86 let filename = filename.extract::<PyBytes>(py)?;
84 87 let filename = filename.data(py);
85 88 Ok((
86 89 HgPathBuf::from(filename.to_owned()),
87 90 DirstateEntry {
88 91 state,
89 92 mode,
90 93 size,
91 94 mtime,
92 95 },
93 96 ))
94 97 })
95 98 .collect()
96 99 }
97 100
98 101 /// Create the module, with `__package__` given from parent
99 102 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
100 103 let dotted_name = &format!("{}.dirstate", package);
101 104 let m = PyModule::new(py, dotted_name)?;
102 105
103 106 m.add(py, "__package__", package)?;
104 107 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
105 108
106 109 m.add_class::<Dirs>(py)?;
107 110 m.add_class::<DirstateMap>(py)?;
111 m.add(
112 py,
113 "status",
114 py_fn!(
115 py,
116 status_wrapper(
117 dmap: DirstateMap,
118 root_dir: PyObject,
119 files: PyList,
120 list_clean: bool,
121 last_normal_time: i64,
122 check_exec: bool
123 )
124 ),
125 )?;
108 126
109 127 let sys = PyModule::import(py, "sys")?;
110 128 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
111 129 sys_modules.set_item(py, dotted_name, &m)?;
112 130
113 131 Ok(m)
114 132 }
@@ -1,510 +1,516 b''
1 1 // dirstate_map.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
9 9 //! `hg-core` package.
10 10
11 use std::cell::RefCell;
11 use std::cell::{Ref, RefCell};
12 12 use std::convert::TryInto;
13 13 use std::time::Duration;
14 14
15 15 use cpython::{
16 16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
17 17 PyResult, PyTuple, Python, PythonObject, ToPyObject,
18 18 };
19 19
20 20 use crate::{
21 21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 22 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
23 23 ref_sharing::{PyLeakedRef, PySharedRefCell},
24 24 };
25 25 use hg::{
26 26 utils::hg_path::{HgPath, HgPathBuf},
27 27 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
28 28 DirstateParents, DirstateParseError, EntryState, StateMapIter,
29 29 PARENT_SIZE,
30 30 };
31 31
32 32 // TODO
33 33 // This object needs to share references to multiple members of its Rust
34 34 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
35 35 // Right now `CopyMap` is done, but it needs to have an explicit reference
36 36 // to `RustDirstateMap` which itself needs to have an encapsulation for
37 37 // every method in `CopyMap` (copymapcopy, etc.).
38 38 // This is ugly and hard to maintain.
39 39 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
40 40 // `py_class!` is already implemented and does not mention
41 41 // `RustDirstateMap`, rightfully so.
42 42 // All attributes also have to have a separate refcount data attribute for
43 43 // leaks, with all methods that go along for reference sharing.
44 44 py_class!(pub class DirstateMap |py| {
45 45 data inner: PySharedRefCell<RustDirstateMap>;
46 46
47 47 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
48 48 let inner = RustDirstateMap::default();
49 49 Self::create_instance(
50 50 py,
51 51 PySharedRefCell::new(inner),
52 52 )
53 53 }
54 54
55 55 def clear(&self) -> PyResult<PyObject> {
56 56 self.inner_shared(py).borrow_mut()?.clear();
57 57 Ok(py.None())
58 58 }
59 59
60 60 def get(
61 61 &self,
62 62 key: PyObject,
63 63 default: Option<PyObject> = None
64 64 ) -> PyResult<Option<PyObject>> {
65 65 let key = key.extract::<PyBytes>(py)?;
66 66 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
67 67 Some(entry) => {
68 68 Ok(Some(make_dirstate_tuple(py, entry)?))
69 69 },
70 70 None => Ok(default)
71 71 }
72 72 }
73 73
74 74 def addfile(
75 75 &self,
76 76 f: PyObject,
77 77 oldstate: PyObject,
78 78 state: PyObject,
79 79 mode: PyObject,
80 80 size: PyObject,
81 81 mtime: PyObject
82 82 ) -> PyResult<PyObject> {
83 83 self.inner_shared(py).borrow_mut()?.add_file(
84 84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
85 85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
86 86 .try_into()
87 87 .map_err(|e: DirstateParseError| {
88 88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
89 89 })?,
90 90 DirstateEntry {
91 91 state: state.extract::<PyBytes>(py)?.data(py)[0]
92 92 .try_into()
93 93 .map_err(|e: DirstateParseError| {
94 94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
95 95 })?,
96 96 mode: mode.extract(py)?,
97 97 size: size.extract(py)?,
98 98 mtime: mtime.extract(py)?,
99 99 },
100 100 );
101 101 Ok(py.None())
102 102 }
103 103
104 104 def removefile(
105 105 &self,
106 106 f: PyObject,
107 107 oldstate: PyObject,
108 108 size: PyObject
109 109 ) -> PyResult<PyObject> {
110 110 self.inner_shared(py).borrow_mut()?
111 111 .remove_file(
112 112 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
113 113 oldstate.extract::<PyBytes>(py)?.data(py)[0]
114 114 .try_into()
115 115 .map_err(|e: DirstateParseError| {
116 116 PyErr::new::<exc::ValueError, _>(py, e.to_string())
117 117 })?,
118 118 size.extract(py)?,
119 119 )
120 120 .or_else(|_| {
121 121 Err(PyErr::new::<exc::OSError, _>(
122 122 py,
123 123 "Dirstate error".to_string(),
124 124 ))
125 125 })?;
126 126 Ok(py.None())
127 127 }
128 128
129 129 def dropfile(
130 130 &self,
131 131 f: PyObject,
132 132 oldstate: PyObject
133 133 ) -> PyResult<PyBool> {
134 134 self.inner_shared(py).borrow_mut()?
135 135 .drop_file(
136 136 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
137 137 oldstate.extract::<PyBytes>(py)?.data(py)[0]
138 138 .try_into()
139 139 .map_err(|e: DirstateParseError| {
140 140 PyErr::new::<exc::ValueError, _>(py, e.to_string())
141 141 })?,
142 142 )
143 143 .and_then(|b| Ok(b.to_py_object(py)))
144 144 .or_else(|_| {
145 145 Err(PyErr::new::<exc::OSError, _>(
146 146 py,
147 147 "Dirstate error".to_string(),
148 148 ))
149 149 })
150 150 }
151 151
152 152 def clearambiguoustimes(
153 153 &self,
154 154 files: PyObject,
155 155 now: PyObject
156 156 ) -> PyResult<PyObject> {
157 157 let files: PyResult<Vec<HgPathBuf>> = files
158 158 .iter(py)?
159 159 .map(|filename| {
160 160 Ok(HgPathBuf::from_bytes(
161 161 filename?.extract::<PyBytes>(py)?.data(py),
162 162 ))
163 163 })
164 164 .collect();
165 165 self.inner_shared(py).borrow_mut()?
166 166 .clear_ambiguous_times(files?, now.extract(py)?);
167 167 Ok(py.None())
168 168 }
169 169
170 170 // TODO share the reference
171 171 def nonnormalentries(&self) -> PyResult<PyObject> {
172 172 let (non_normal, other_parent) =
173 173 self.inner(py).borrow().non_normal_other_parent_entries();
174 174
175 175 let locals = PyDict::new(py);
176 176 locals.set_item(
177 177 py,
178 178 "non_normal",
179 179 non_normal
180 180 .iter()
181 181 .map(|v| PyBytes::new(py, v.as_ref()))
182 182 .collect::<Vec<PyBytes>>()
183 183 .to_py_object(py),
184 184 )?;
185 185 locals.set_item(
186 186 py,
187 187 "other_parent",
188 188 other_parent
189 189 .iter()
190 190 .map(|v| PyBytes::new(py, v.as_ref()))
191 191 .collect::<Vec<PyBytes>>()
192 192 .to_py_object(py),
193 193 )?;
194 194
195 195 py.eval("set(non_normal), set(other_parent)", None, Some(&locals))
196 196 }
197 197
198 198 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
199 199 let d = d.extract::<PyBytes>(py)?;
200 200 Ok(self.inner_shared(py).borrow_mut()?
201 201 .has_tracked_dir(HgPath::new(d.data(py)))
202 202 .to_py_object(py))
203 203 }
204 204
205 205 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
206 206 let d = d.extract::<PyBytes>(py)?;
207 207 Ok(self.inner_shared(py).borrow_mut()?
208 208 .has_dir(HgPath::new(d.data(py)))
209 209 .to_py_object(py))
210 210 }
211 211
212 212 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
213 213 self.inner_shared(py).borrow_mut()?
214 214 .parents(st.extract::<PyBytes>(py)?.data(py))
215 215 .and_then(|d| {
216 216 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
217 217 .to_py_object(py))
218 218 })
219 219 .or_else(|_| {
220 220 Err(PyErr::new::<exc::OSError, _>(
221 221 py,
222 222 "Dirstate error".to_string(),
223 223 ))
224 224 })
225 225 }
226 226
227 227 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
228 228 let p1 = extract_node_id(py, &p1)?;
229 229 let p2 = extract_node_id(py, &p2)?;
230 230
231 231 self.inner_shared(py).borrow_mut()?
232 232 .set_parents(&DirstateParents { p1, p2 });
233 233 Ok(py.None())
234 234 }
235 235
236 236 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
237 237 match self.inner_shared(py).borrow_mut()?
238 238 .read(st.extract::<PyBytes>(py)?.data(py))
239 239 {
240 240 Ok(Some(parents)) => Ok(Some(
241 241 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
242 242 .to_py_object(py)
243 243 .into_object(),
244 244 )),
245 245 Ok(None) => Ok(Some(py.None())),
246 246 Err(_) => Err(PyErr::new::<exc::OSError, _>(
247 247 py,
248 248 "Dirstate error".to_string(),
249 249 )),
250 250 }
251 251 }
252 252 def write(
253 253 &self,
254 254 p1: PyObject,
255 255 p2: PyObject,
256 256 now: PyObject
257 257 ) -> PyResult<PyBytes> {
258 258 let now = Duration::new(now.extract(py)?, 0);
259 259 let parents = DirstateParents {
260 260 p1: extract_node_id(py, &p1)?,
261 261 p2: extract_node_id(py, &p2)?,
262 262 };
263 263
264 264 match self.inner_shared(py).borrow_mut()?.pack(parents, now) {
265 265 Ok(packed) => Ok(PyBytes::new(py, &packed)),
266 266 Err(_) => Err(PyErr::new::<exc::OSError, _>(
267 267 py,
268 268 "Dirstate error".to_string(),
269 269 )),
270 270 }
271 271 }
272 272
273 273 def filefoldmapasdict(&self) -> PyResult<PyDict> {
274 274 let dict = PyDict::new(py);
275 275 for (key, value) in
276 276 self.inner_shared(py).borrow_mut()?.build_file_fold_map().iter()
277 277 {
278 278 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
279 279 }
280 280 Ok(dict)
281 281 }
282 282
283 283 def __len__(&self) -> PyResult<usize> {
284 284 Ok(self.inner(py).borrow().len())
285 285 }
286 286
287 287 def __contains__(&self, key: PyObject) -> PyResult<bool> {
288 288 let key = key.extract::<PyBytes>(py)?;
289 289 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
290 290 }
291 291
292 292 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
293 293 let key = key.extract::<PyBytes>(py)?;
294 294 let key = HgPath::new(key.data(py));
295 295 match self.inner(py).borrow().get(key) {
296 296 Some(entry) => {
297 297 Ok(make_dirstate_tuple(py, entry)?)
298 298 },
299 299 None => Err(PyErr::new::<exc::KeyError, _>(
300 300 py,
301 301 String::from_utf8_lossy(key.as_bytes()),
302 302 )),
303 303 }
304 304 }
305 305
306 306 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
307 307 let (leak_handle, leaked_ref) =
308 308 unsafe { self.inner_shared(py).leak_immutable()? };
309 309 DirstateMapKeysIterator::from_inner(
310 310 py,
311 311 leak_handle,
312 312 leaked_ref.iter(),
313 313 )
314 314 }
315 315
316 316 def items(&self) -> PyResult<DirstateMapItemsIterator> {
317 317 let (leak_handle, leaked_ref) =
318 318 unsafe { self.inner_shared(py).leak_immutable()? };
319 319 DirstateMapItemsIterator::from_inner(
320 320 py,
321 321 leak_handle,
322 322 leaked_ref.iter(),
323 323 )
324 324 }
325 325
326 326 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
327 327 let (leak_handle, leaked_ref) =
328 328 unsafe { self.inner_shared(py).leak_immutable()? };
329 329 DirstateMapKeysIterator::from_inner(
330 330 py,
331 331 leak_handle,
332 332 leaked_ref.iter(),
333 333 )
334 334 }
335 335
336 336 def getdirs(&self) -> PyResult<Dirs> {
337 337 // TODO don't copy, share the reference
338 338 self.inner_shared(py).borrow_mut()?.set_dirs();
339 339 Dirs::from_inner(
340 340 py,
341 341 DirsMultiset::from_dirstate(
342 342 &self.inner(py).borrow(),
343 343 Some(EntryState::Removed),
344 344 ),
345 345 )
346 346 }
347 347 def getalldirs(&self) -> PyResult<Dirs> {
348 348 // TODO don't copy, share the reference
349 349 self.inner_shared(py).borrow_mut()?.set_all_dirs();
350 350 Dirs::from_inner(
351 351 py,
352 352 DirsMultiset::from_dirstate(
353 353 &self.inner(py).borrow(),
354 354 None,
355 355 ),
356 356 )
357 357 }
358 358
359 359 // TODO all copymap* methods, see docstring above
360 360 def copymapcopy(&self) -> PyResult<PyDict> {
361 361 let dict = PyDict::new(py);
362 362 for (key, value) in self.inner(py).borrow().copy_map.iter() {
363 363 dict.set_item(
364 364 py,
365 365 PyBytes::new(py, key.as_ref()),
366 366 PyBytes::new(py, value.as_ref()),
367 367 )?;
368 368 }
369 369 Ok(dict)
370 370 }
371 371
372 372 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
373 373 let key = key.extract::<PyBytes>(py)?;
374 374 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
375 375 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
376 376 None => Err(PyErr::new::<exc::KeyError, _>(
377 377 py,
378 378 String::from_utf8_lossy(key.data(py)),
379 379 )),
380 380 }
381 381 }
382 382 def copymap(&self) -> PyResult<CopyMap> {
383 383 CopyMap::from_inner(py, self.clone_ref(py))
384 384 }
385 385
386 386 def copymaplen(&self) -> PyResult<usize> {
387 387 Ok(self.inner(py).borrow().copy_map.len())
388 388 }
389 389 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
390 390 let key = key.extract::<PyBytes>(py)?;
391 391 Ok(self
392 392 .inner(py)
393 393 .borrow()
394 394 .copy_map
395 395 .contains_key(HgPath::new(key.data(py))))
396 396 }
397 397 def copymapget(
398 398 &self,
399 399 key: PyObject,
400 400 default: Option<PyObject>
401 401 ) -> PyResult<Option<PyObject>> {
402 402 let key = key.extract::<PyBytes>(py)?;
403 403 match self
404 404 .inner(py)
405 405 .borrow()
406 406 .copy_map
407 407 .get(HgPath::new(key.data(py)))
408 408 {
409 409 Some(copy) => Ok(Some(
410 410 PyBytes::new(py, copy.as_ref()).into_object(),
411 411 )),
412 412 None => Ok(default),
413 413 }
414 414 }
415 415 def copymapsetitem(
416 416 &self,
417 417 key: PyObject,
418 418 value: PyObject
419 419 ) -> PyResult<PyObject> {
420 420 let key = key.extract::<PyBytes>(py)?;
421 421 let value = value.extract::<PyBytes>(py)?;
422 422 self.inner_shared(py).borrow_mut()?.copy_map.insert(
423 423 HgPathBuf::from_bytes(key.data(py)),
424 424 HgPathBuf::from_bytes(value.data(py)),
425 425 );
426 426 Ok(py.None())
427 427 }
428 428 def copymappop(
429 429 &self,
430 430 key: PyObject,
431 431 default: Option<PyObject>
432 432 ) -> PyResult<Option<PyObject>> {
433 433 let key = key.extract::<PyBytes>(py)?;
434 434 match self
435 435 .inner_shared(py)
436 436 .borrow_mut()?
437 437 .copy_map
438 438 .remove(HgPath::new(key.data(py)))
439 439 {
440 440 Some(_) => Ok(None),
441 441 None => Ok(default),
442 442 }
443 443 }
444 444
445 445 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
446 446 let (leak_handle, leaked_ref) =
447 447 unsafe { self.inner_shared(py).leak_immutable()? };
448 448 CopyMapKeysIterator::from_inner(
449 449 py,
450 450 leak_handle,
451 451 leaked_ref.copy_map.iter(),
452 452 )
453 453 }
454 454
455 455 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
456 456 let (leak_handle, leaked_ref) =
457 457 unsafe { self.inner_shared(py).leak_immutable()? };
458 458 CopyMapItemsIterator::from_inner(
459 459 py,
460 460 leak_handle,
461 461 leaked_ref.copy_map.iter(),
462 462 )
463 463 }
464 464
465 465 });
466 466
467 467 impl DirstateMap {
468 pub fn get_inner<'a>(
469 &'a self,
470 py: Python<'a>,
471 ) -> Ref<'a, RustDirstateMap> {
472 self.inner_shared(py).borrow()
473 }
468 474 fn translate_key(
469 475 py: Python,
470 476 res: (&HgPathBuf, &DirstateEntry),
471 477 ) -> PyResult<Option<PyBytes>> {
472 478 Ok(Some(PyBytes::new(py, res.0.as_ref())))
473 479 }
474 480 fn translate_key_value(
475 481 py: Python,
476 482 res: (&HgPathBuf, &DirstateEntry),
477 483 ) -> PyResult<Option<(PyBytes, PyObject)>> {
478 484 let (f, entry) = res;
479 485 Ok(Some((
480 486 PyBytes::new(py, f.as_ref()),
481 487 make_dirstate_tuple(py, entry)?,
482 488 )))
483 489 }
484 490 }
485 491
486 492 py_shared_ref!(DirstateMap, RustDirstateMap, inner, inner_shared);
487 493
488 494 py_shared_iterator!(
489 495 DirstateMapKeysIterator,
490 496 PyLeakedRef,
491 497 StateMapIter<'static>,
492 498 DirstateMap::translate_key,
493 499 Option<PyBytes>
494 500 );
495 501
496 502 py_shared_iterator!(
497 503 DirstateMapItemsIterator,
498 504 PyLeakedRef,
499 505 StateMapIter<'static>,
500 506 DirstateMap::translate_key_value,
501 507 Option<(PyBytes, PyObject)>
502 508 );
503 509
504 510 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
505 511 let bytes = obj.extract::<PyBytes>(py)?;
506 512 match bytes.data(py).try_into() {
507 513 Ok(s) => Ok(s),
508 514 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
509 515 }
510 516 }
General Comments 0
You need to be logged in to leave comments. Login now