##// END OF EJS Templates
rust-format: make rustfmt happy...
Raphaël Gomès -
r44923:927137fc stable
parent child Browse files
Show More
@@ -1,577 +1,582 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 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, PyList,
17 17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 18 };
19 19
20 20 use crate::{
21 21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 22 dirstate::non_normal_entries::NonNormalEntries,
23 23 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
24 24 ref_sharing::{PyLeaked, PySharedRefCell},
25 25 };
26 26 use hg::{
27 27 utils::hg_path::{HgPath, HgPathBuf},
28 28 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
29 29 DirstateMapError, DirstateParents, DirstateParseError, EntryState,
30 30 StateMapIter, PARENT_SIZE,
31 31 };
32 32
33 33 // TODO
34 34 // This object needs to share references to multiple members of its Rust
35 35 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
36 36 // Right now `CopyMap` is done, but it needs to have an explicit reference
37 37 // to `RustDirstateMap` which itself needs to have an encapsulation for
38 38 // every method in `CopyMap` (copymapcopy, etc.).
39 39 // This is ugly and hard to maintain.
40 40 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
41 41 // `py_class!` is already implemented and does not mention
42 42 // `RustDirstateMap`, rightfully so.
43 43 // All attributes also have to have a separate refcount data attribute for
44 44 // leaks, with all methods that go along for reference sharing.
45 45 py_class!(pub class DirstateMap |py| {
46 46 data inner: PySharedRefCell<RustDirstateMap>;
47 47
48 48 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
49 49 let inner = RustDirstateMap::default();
50 50 Self::create_instance(
51 51 py,
52 52 PySharedRefCell::new(inner),
53 53 )
54 54 }
55 55
56 56 def clear(&self) -> PyResult<PyObject> {
57 57 self.inner_shared(py).borrow_mut()?.clear();
58 58 Ok(py.None())
59 59 }
60 60
61 61 def get(
62 62 &self,
63 63 key: PyObject,
64 64 default: Option<PyObject> = None
65 65 ) -> PyResult<Option<PyObject>> {
66 66 let key = key.extract::<PyBytes>(py)?;
67 67 match self.inner_shared(py).borrow().get(HgPath::new(key.data(py))) {
68 68 Some(entry) => {
69 69 Ok(Some(make_dirstate_tuple(py, entry)?))
70 70 },
71 71 None => Ok(default)
72 72 }
73 73 }
74 74
75 75 def addfile(
76 76 &self,
77 77 f: PyObject,
78 78 oldstate: PyObject,
79 79 state: PyObject,
80 80 mode: PyObject,
81 81 size: PyObject,
82 82 mtime: PyObject
83 83 ) -> PyResult<PyObject> {
84 84 self.inner_shared(py).borrow_mut()?.add_file(
85 85 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
86 86 oldstate.extract::<PyBytes>(py)?.data(py)[0]
87 87 .try_into()
88 88 .map_err(|e: DirstateParseError| {
89 89 PyErr::new::<exc::ValueError, _>(py, e.to_string())
90 90 })?,
91 91 DirstateEntry {
92 92 state: state.extract::<PyBytes>(py)?.data(py)[0]
93 93 .try_into()
94 94 .map_err(|e: DirstateParseError| {
95 95 PyErr::new::<exc::ValueError, _>(py, e.to_string())
96 96 })?,
97 97 mode: mode.extract(py)?,
98 98 size: size.extract(py)?,
99 99 mtime: mtime.extract(py)?,
100 100 },
101 101 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
102 102 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
103 103 })
104 104 }
105 105
106 106 def removefile(
107 107 &self,
108 108 f: PyObject,
109 109 oldstate: PyObject,
110 110 size: PyObject
111 111 ) -> PyResult<PyObject> {
112 112 self.inner_shared(py).borrow_mut()?
113 113 .remove_file(
114 114 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
115 115 oldstate.extract::<PyBytes>(py)?.data(py)[0]
116 116 .try_into()
117 117 .map_err(|e: DirstateParseError| {
118 118 PyErr::new::<exc::ValueError, _>(py, e.to_string())
119 119 })?,
120 120 size.extract(py)?,
121 121 )
122 122 .or_else(|_| {
123 123 Err(PyErr::new::<exc::OSError, _>(
124 124 py,
125 125 "Dirstate error".to_string(),
126 126 ))
127 127 })?;
128 128 Ok(py.None())
129 129 }
130 130
131 131 def dropfile(
132 132 &self,
133 133 f: PyObject,
134 134 oldstate: PyObject
135 135 ) -> PyResult<PyBool> {
136 136 self.inner_shared(py).borrow_mut()?
137 137 .drop_file(
138 138 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
139 139 oldstate.extract::<PyBytes>(py)?.data(py)[0]
140 140 .try_into()
141 141 .map_err(|e: DirstateParseError| {
142 142 PyErr::new::<exc::ValueError, _>(py, e.to_string())
143 143 })?,
144 144 )
145 145 .and_then(|b| Ok(b.to_py_object(py)))
146 146 .or_else(|_| {
147 147 Err(PyErr::new::<exc::OSError, _>(
148 148 py,
149 149 "Dirstate error".to_string(),
150 150 ))
151 151 })
152 152 }
153 153
154 154 def clearambiguoustimes(
155 155 &self,
156 156 files: PyObject,
157 157 now: PyObject
158 158 ) -> PyResult<PyObject> {
159 159 let files: PyResult<Vec<HgPathBuf>> = files
160 160 .iter(py)?
161 161 .map(|filename| {
162 162 Ok(HgPathBuf::from_bytes(
163 163 filename?.extract::<PyBytes>(py)?.data(py),
164 164 ))
165 165 })
166 166 .collect();
167 167 self.inner_shared(py).borrow_mut()?
168 168 .clear_ambiguous_times(files?, now.extract(py)?);
169 169 Ok(py.None())
170 170 }
171 171
172 172 def other_parent_entries(&self) -> PyResult<PyObject> {
173 173 let mut inner_shared = self.inner_shared(py).borrow_mut()?;
174 174 let (_, other_parent) =
175 175 inner_shared.get_non_normal_other_parent_entries();
176 176
177 177 let locals = PyDict::new(py);
178 178 locals.set_item(
179 179 py,
180 180 "other_parent",
181 181 other_parent.as_ref()
182 182 .unwrap()
183 183 .iter()
184 184 .map(|v| PyBytes::new(py, v.as_ref()))
185 185 .collect::<Vec<PyBytes>>()
186 186 .to_py_object(py),
187 187 )?;
188 188
189 189 py.eval("set(other_parent)", None, Some(&locals))
190 190 }
191 191
192 192 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
193 193 NonNormalEntries::from_inner(py, self.clone_ref(py))
194 194 }
195 195
196 196 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
197 197 let key = key.extract::<PyBytes>(py)?;
198 198 Ok(self
199 199 .inner_shared(py)
200 200 .borrow_mut()?
201 201 .get_non_normal_other_parent_entries().0
202 202 .as_ref()
203 203 .unwrap()
204 204 .contains(HgPath::new(key.data(py))))
205 205 }
206 206
207 207 def non_normal_entries_display(&self) -> PyResult<PyString> {
208 208 Ok(
209 209 PyString::new(
210 210 py,
211 211 &format!(
212 212 "NonNormalEntries: {:?}",
213 213 self
214 214 .inner_shared(py)
215 215 .borrow_mut()?
216 216 .get_non_normal_other_parent_entries().0
217 217 .as_ref()
218 218 .unwrap().iter().map(|o| o))
219 219 )
220 220 )
221 221 }
222 222
223 223 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
224 224 let key = key.extract::<PyBytes>(py)?;
225 225 self
226 226 .inner_shared(py)
227 227 .borrow_mut()?
228 228 .non_normal_entries_remove(HgPath::new(key.data(py)));
229 229 Ok(py.None())
230 230 }
231 231
232 232 def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
233 233 let other: PyResult<_> = other.iter(py)?
234 234 .map(|f| {
235 235 Ok(HgPathBuf::from_bytes(
236 236 f?.extract::<PyBytes>(py)?.data(py),
237 237 ))
238 238 })
239 239 .collect();
240 240
241 241 let res = self
242 242 .inner_shared(py)
243 243 .borrow_mut()?
244 244 .non_normal_entries_union(other?);
245 245
246 246 let ret = PyList::new(py, &[]);
247 247 for (i, filename) in res.iter().enumerate() {
248 248 let as_pystring = PyBytes::new(py, filename.as_bytes());
249 249 ret.insert_item(py, i, as_pystring.into_object());
250 250 }
251 251 Ok(ret)
252 252 }
253 253
254 254 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
255 255 let d = d.extract::<PyBytes>(py)?;
256 256 Ok(self.inner_shared(py).borrow_mut()?
257 257 .has_tracked_dir(HgPath::new(d.data(py)))
258 258 .map_err(|e| {
259 259 PyErr::new::<exc::ValueError, _>(py, e.to_string())
260 260 })?
261 261 .to_py_object(py))
262 262 }
263 263
264 264 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
265 265 let d = d.extract::<PyBytes>(py)?;
266 266 Ok(self.inner_shared(py).borrow_mut()?
267 267 .has_dir(HgPath::new(d.data(py)))
268 268 .map_err(|e| {
269 269 PyErr::new::<exc::ValueError, _>(py, e.to_string())
270 270 })?
271 271 .to_py_object(py))
272 272 }
273 273
274 274 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
275 275 self.inner_shared(py).borrow_mut()?
276 276 .parents(st.extract::<PyBytes>(py)?.data(py))
277 277 .and_then(|d| {
278 278 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
279 279 .to_py_object(py))
280 280 })
281 281 .or_else(|_| {
282 282 Err(PyErr::new::<exc::OSError, _>(
283 283 py,
284 284 "Dirstate error".to_string(),
285 285 ))
286 286 })
287 287 }
288 288
289 289 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
290 290 let p1 = extract_node_id(py, &p1)?;
291 291 let p2 = extract_node_id(py, &p2)?;
292 292
293 293 self.inner_shared(py).borrow_mut()?
294 294 .set_parents(&DirstateParents { p1, p2 });
295 295 Ok(py.None())
296 296 }
297 297
298 298 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
299 299 match self.inner_shared(py).borrow_mut()?
300 300 .read(st.extract::<PyBytes>(py)?.data(py))
301 301 {
302 302 Ok(Some(parents)) => Ok(Some(
303 303 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
304 304 .to_py_object(py)
305 305 .into_object(),
306 306 )),
307 307 Ok(None) => Ok(Some(py.None())),
308 308 Err(_) => Err(PyErr::new::<exc::OSError, _>(
309 309 py,
310 310 "Dirstate error".to_string(),
311 311 )),
312 312 }
313 313 }
314 314 def write(
315 315 &self,
316 316 p1: PyObject,
317 317 p2: PyObject,
318 318 now: PyObject
319 319 ) -> PyResult<PyBytes> {
320 320 let now = Duration::new(now.extract(py)?, 0);
321 321 let parents = DirstateParents {
322 322 p1: extract_node_id(py, &p1)?,
323 323 p2: extract_node_id(py, &p2)?,
324 324 };
325 325
326 326 match self.inner_shared(py).borrow_mut()?.pack(parents, now) {
327 327 Ok(packed) => Ok(PyBytes::new(py, &packed)),
328 328 Err(_) => Err(PyErr::new::<exc::OSError, _>(
329 329 py,
330 330 "Dirstate error".to_string(),
331 331 )),
332 332 }
333 333 }
334 334
335 335 def filefoldmapasdict(&self) -> PyResult<PyDict> {
336 336 let dict = PyDict::new(py);
337 337 for (key, value) in
338 338 self.inner_shared(py).borrow_mut()?.build_file_fold_map().iter()
339 339 {
340 340 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
341 341 }
342 342 Ok(dict)
343 343 }
344 344
345 345 def __len__(&self) -> PyResult<usize> {
346 346 Ok(self.inner_shared(py).borrow().len())
347 347 }
348 348
349 349 def __contains__(&self, key: PyObject) -> PyResult<bool> {
350 350 let key = key.extract::<PyBytes>(py)?;
351 Ok(self.inner_shared(py).borrow().contains_key(HgPath::new(key.data(py))))
351 Ok(self.inner_shared(py)
352 .borrow()
353 .contains_key(HgPath::new(key.data(py))))
352 354 }
353 355
354 356 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
355 357 let key = key.extract::<PyBytes>(py)?;
356 358 let key = HgPath::new(key.data(py));
357 359 match self.inner_shared(py).borrow().get(key) {
358 360 Some(entry) => {
359 361 Ok(make_dirstate_tuple(py, entry)?)
360 362 },
361 363 None => Err(PyErr::new::<exc::KeyError, _>(
362 364 py,
363 365 String::from_utf8_lossy(key.as_bytes()),
364 366 )),
365 367 }
366 368 }
367 369
368 370 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
369 371 let leaked_ref = self.inner_shared(py).leak_immutable();
370 372 DirstateMapKeysIterator::from_inner(
371 373 py,
372 374 unsafe { leaked_ref.map(py, |o| o.iter()) },
373 375 )
374 376 }
375 377
376 378 def items(&self) -> PyResult<DirstateMapItemsIterator> {
377 379 let leaked_ref = self.inner_shared(py).leak_immutable();
378 380 DirstateMapItemsIterator::from_inner(
379 381 py,
380 382 unsafe { leaked_ref.map(py, |o| o.iter()) },
381 383 )
382 384 }
383 385
384 386 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
385 387 let leaked_ref = self.inner_shared(py).leak_immutable();
386 388 DirstateMapKeysIterator::from_inner(
387 389 py,
388 390 unsafe { leaked_ref.map(py, |o| o.iter()) },
389 391 )
390 392 }
391 393
392 394 def getdirs(&self) -> PyResult<Dirs> {
393 395 // TODO don't copy, share the reference
394 396 self.inner_shared(py).borrow_mut()?.set_dirs()
395 397 .map_err(|e| {
396 398 PyErr::new::<exc::ValueError, _>(py, e.to_string())
397 399 })?;
398 400 Dirs::from_inner(
399 401 py,
400 402 DirsMultiset::from_dirstate(
401 403 &self.inner_shared(py).borrow(),
402 404 Some(EntryState::Removed),
403 405 )
404 406 .map_err(|e| {
405 407 PyErr::new::<exc::ValueError, _>(py, e.to_string())
406 408 })?,
407 409 )
408 410 }
409 411 def getalldirs(&self) -> PyResult<Dirs> {
410 412 // TODO don't copy, share the reference
411 413 self.inner_shared(py).borrow_mut()?.set_all_dirs()
412 414 .map_err(|e| {
413 415 PyErr::new::<exc::ValueError, _>(py, e.to_string())
414 416 })?;
415 417 Dirs::from_inner(
416 418 py,
417 419 DirsMultiset::from_dirstate(
418 420 &self.inner_shared(py).borrow(),
419 421 None,
420 422 ).map_err(|e| {
421 423 PyErr::new::<exc::ValueError, _>(py, e.to_string())
422 424 })?,
423 425 )
424 426 }
425 427
426 428 // TODO all copymap* methods, see docstring above
427 429 def copymapcopy(&self) -> PyResult<PyDict> {
428 430 let dict = PyDict::new(py);
429 431 for (key, value) in self.inner_shared(py).borrow().copy_map.iter() {
430 432 dict.set_item(
431 433 py,
432 434 PyBytes::new(py, key.as_ref()),
433 435 PyBytes::new(py, value.as_ref()),
434 436 )?;
435 437 }
436 438 Ok(dict)
437 439 }
438 440
439 441 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
440 442 let key = key.extract::<PyBytes>(py)?;
441 match self.inner_shared(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
443 match self.inner_shared(py)
444 .borrow()
445 .copy_map
446 .get(HgPath::new(key.data(py))) {
442 447 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
443 448 None => Err(PyErr::new::<exc::KeyError, _>(
444 449 py,
445 450 String::from_utf8_lossy(key.data(py)),
446 451 )),
447 452 }
448 453 }
449 454 def copymap(&self) -> PyResult<CopyMap> {
450 455 CopyMap::from_inner(py, self.clone_ref(py))
451 456 }
452 457
453 458 def copymaplen(&self) -> PyResult<usize> {
454 459 Ok(self.inner_shared(py).borrow().copy_map.len())
455 460 }
456 461 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
457 462 let key = key.extract::<PyBytes>(py)?;
458 463 Ok(self
459 464 .inner_shared(py)
460 465 .borrow()
461 466 .copy_map
462 467 .contains_key(HgPath::new(key.data(py))))
463 468 }
464 469 def copymapget(
465 470 &self,
466 471 key: PyObject,
467 472 default: Option<PyObject>
468 473 ) -> PyResult<Option<PyObject>> {
469 474 let key = key.extract::<PyBytes>(py)?;
470 475 match self
471 476 .inner_shared(py)
472 477 .borrow()
473 478 .copy_map
474 479 .get(HgPath::new(key.data(py)))
475 480 {
476 481 Some(copy) => Ok(Some(
477 482 PyBytes::new(py, copy.as_ref()).into_object(),
478 483 )),
479 484 None => Ok(default),
480 485 }
481 486 }
482 487 def copymapsetitem(
483 488 &self,
484 489 key: PyObject,
485 490 value: PyObject
486 491 ) -> PyResult<PyObject> {
487 492 let key = key.extract::<PyBytes>(py)?;
488 493 let value = value.extract::<PyBytes>(py)?;
489 494 self.inner_shared(py).borrow_mut()?.copy_map.insert(
490 495 HgPathBuf::from_bytes(key.data(py)),
491 496 HgPathBuf::from_bytes(value.data(py)),
492 497 );
493 498 Ok(py.None())
494 499 }
495 500 def copymappop(
496 501 &self,
497 502 key: PyObject,
498 503 default: Option<PyObject>
499 504 ) -> PyResult<Option<PyObject>> {
500 505 let key = key.extract::<PyBytes>(py)?;
501 506 match self
502 507 .inner_shared(py)
503 508 .borrow_mut()?
504 509 .copy_map
505 510 .remove(HgPath::new(key.data(py)))
506 511 {
507 512 Some(_) => Ok(None),
508 513 None => Ok(default),
509 514 }
510 515 }
511 516
512 517 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
513 518 let leaked_ref = self.inner_shared(py).leak_immutable();
514 519 CopyMapKeysIterator::from_inner(
515 520 py,
516 521 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
517 522 )
518 523 }
519 524
520 525 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
521 526 let leaked_ref = self.inner_shared(py).leak_immutable();
522 527 CopyMapItemsIterator::from_inner(
523 528 py,
524 529 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
525 530 )
526 531 }
527 532
528 533 });
529 534
530 535 impl DirstateMap {
531 536 pub fn get_inner<'a>(
532 537 &'a self,
533 538 py: Python<'a>,
534 539 ) -> Ref<'a, RustDirstateMap> {
535 540 self.inner_shared(py).borrow()
536 541 }
537 542 fn translate_key(
538 543 py: Python,
539 544 res: (&HgPathBuf, &DirstateEntry),
540 545 ) -> PyResult<Option<PyBytes>> {
541 546 Ok(Some(PyBytes::new(py, res.0.as_ref())))
542 547 }
543 548 fn translate_key_value(
544 549 py: Python,
545 550 res: (&HgPathBuf, &DirstateEntry),
546 551 ) -> PyResult<Option<(PyBytes, PyObject)>> {
547 552 let (f, entry) = res;
548 553 Ok(Some((
549 554 PyBytes::new(py, f.as_ref()),
550 555 make_dirstate_tuple(py, entry)?,
551 556 )))
552 557 }
553 558 }
554 559
555 560 py_shared_ref!(DirstateMap, RustDirstateMap, inner, inner_shared);
556 561
557 562 py_shared_iterator!(
558 563 DirstateMapKeysIterator,
559 564 PyLeaked<StateMapIter<'static>>,
560 565 DirstateMap::translate_key,
561 566 Option<PyBytes>
562 567 );
563 568
564 569 py_shared_iterator!(
565 570 DirstateMapItemsIterator,
566 571 PyLeaked<StateMapIter<'static>>,
567 572 DirstateMap::translate_key_value,
568 573 Option<(PyBytes, PyObject)>
569 574 );
570 575
571 576 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
572 577 let bytes = obj.extract::<PyBytes>(py)?;
573 578 match bytes.data(py).try_into() {
574 579 Ok(s) => Ok(s),
575 580 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
576 581 }
577 582 }
General Comments 0
You need to be logged in to leave comments. Login now