rust-dirstatemap: add `NonNormalEntries` class
This fix introduces the same encapsulation as the `copymap`. There is no easy
way of doing this any better for now.
`hg up -r null && time HGRCPATH= HGMODULEPOLICY=rust+c hg up tip` on Mozilla
Central, (not super recent, but it doesn't matter):
Before: 7:44,08 total
After: 1:03,23 total
Pretty brutal regression!
This is a graft on stable of
cf1f8660e568
Differential Revision: https://phab.mercurial-scm.org/D8111
--- a/mercurial/dirstate.py Thu Jan 30 14:57:02 2020 +0100
+++ b/mercurial/dirstate.py Wed Feb 12 23:23:59 2020 +0100
@@ -1846,12 +1846,12 @@
@property
def nonnormalset(self):
- nonnorm, otherparents = self._rustmap.nonnormalentries()
+ nonnorm = self._rustmap.non_normal_entries()
return nonnorm
@propertycache
def otherparentset(self):
- nonnorm, otherparents = self._rustmap.nonnormalentries()
+ otherparents = self._rustmap.other_parent_entries()
return otherparents
@propertycache
--- a/rust/hg-cpython/src/dirstate.rs Thu Jan 30 14:57:02 2020 +0100
+++ b/rust/hg-cpython/src/dirstate.rs Wed Feb 12 23:23:59 2020 +0100
@@ -12,6 +12,7 @@
mod copymap;
mod dirs_multiset;
mod dirstate_map;
+mod non_normal_entries;
mod status;
use crate::dirstate::{
dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Thu Jan 30 14:57:02 2020 +0100
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Wed Feb 12 23:23:59 2020 +0100
@@ -13,12 +13,13 @@
use std::time::Duration;
use cpython::{
- exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
- PyResult, PyTuple, Python, PythonObject, ToPyObject,
+ exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
+ PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
};
use crate::{
dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
+ dirstate::non_normal_entries::NonNormalEntries,
dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
ref_sharing::{PyLeaked, PySharedRefCell},
};
@@ -168,32 +169,86 @@
Ok(py.None())
}
- // TODO share the reference
- def nonnormalentries(&self) -> PyResult<PyObject> {
- let (non_normal, other_parent) =
- self.inner_shared(py).borrow().non_normal_other_parent_entries();
+ def other_parent_entries(&self) -> PyResult<PyObject> {
+ let mut inner_shared = self.inner_shared(py).borrow_mut()?;
+ let (_, other_parent) =
+ inner_shared.get_non_normal_other_parent_entries();
let locals = PyDict::new(py);
locals.set_item(
py,
- "non_normal",
- non_normal
- .iter()
- .map(|v| PyBytes::new(py, v.as_ref()))
- .collect::<Vec<PyBytes>>()
- .to_py_object(py),
- )?;
- locals.set_item(
- py,
"other_parent",
- other_parent
+ other_parent.as_ref()
+ .unwrap()
.iter()
.map(|v| PyBytes::new(py, v.as_ref()))
.collect::<Vec<PyBytes>>()
.to_py_object(py),
)?;
- py.eval("set(non_normal), set(other_parent)", None, Some(&locals))
+ py.eval("set(other_parent)", None, Some(&locals))
+ }
+
+ def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
+ NonNormalEntries::from_inner(py, self.clone_ref(py))
+ }
+
+ def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
+ let key = key.extract::<PyBytes>(py)?;
+ Ok(self
+ .inner_shared(py)
+ .borrow_mut()?
+ .get_non_normal_other_parent_entries().0
+ .as_ref()
+ .unwrap()
+ .contains(HgPath::new(key.data(py))))
+ }
+
+ def non_normal_entries_display(&self) -> PyResult<PyString> {
+ Ok(
+ PyString::new(
+ py,
+ &format!(
+ "NonNormalEntries: {:?}",
+ self
+ .inner_shared(py)
+ .borrow_mut()?
+ .get_non_normal_other_parent_entries().0
+ .as_ref()
+ .unwrap().iter().map(|o| o))
+ )
+ )
+ }
+
+ def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
+ let key = key.extract::<PyBytes>(py)?;
+ self
+ .inner_shared(py)
+ .borrow_mut()?
+ .non_normal_entries_remove(HgPath::new(key.data(py)));
+ Ok(py.None())
+ }
+
+ def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
+ let other: PyResult<_> = other.iter(py)?
+ .map(|f| {
+ Ok(HgPathBuf::from_bytes(
+ f?.extract::<PyBytes>(py)?.data(py),
+ ))
+ })
+ .collect();
+
+ let res = self
+ .inner_shared(py)
+ .borrow_mut()?
+ .non_normal_entries_union(other?);
+
+ let ret = PyList::new(py, &[]);
+ for (i, filename) in res.iter().enumerate() {
+ let as_pystring = PyBytes::new(py, filename.as_bytes());
+ ret.insert_item(py, i, as_pystring.into_object());
+ }
+ Ok(ret)
}
def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hg-cpython/src/dirstate/non_normal_entries.rs Wed Feb 12 23:23:59 2020 +0100
@@ -0,0 +1,52 @@
+// non_normal_other_parent_entries.rs
+//
+// Copyright 2020 Raphaël Gomès <rgomes@octobus.net>
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+
+use cpython::{
+ exc::NotImplementedError, CompareOp, ObjectProtocol, PyErr, PyList,
+ PyObject, PyResult, PyString, Python, PythonObject, ToPyObject,
+};
+
+use crate::dirstate::DirstateMap;
+
+py_class!(pub class NonNormalEntries |py| {
+ data dmap: DirstateMap;
+
+ def __contains__(&self, key: PyObject) -> PyResult<bool> {
+ self.dmap(py).non_normal_entries_contains(py, key)
+ }
+ def remove(&self, key: PyObject) -> PyResult<PyObject> {
+ self.dmap(py).non_normal_entries_remove(py, key)
+ }
+ def union(&self, other: PyObject) -> PyResult<PyList> {
+ self.dmap(py).non_normal_entries_union(py, other)
+ }
+ def __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult<bool> {
+ match op {
+ CompareOp::Eq => self.is_equal_to(py, other),
+ CompareOp::Ne => Ok(!self.is_equal_to(py, other)?),
+ _ => Err(PyErr::new::<NotImplementedError, _>(py, ""))
+ }
+ }
+ def __repr__(&self) -> PyResult<PyString> {
+ self.dmap(py).non_normal_entries_display(py)
+ }
+});
+
+impl NonNormalEntries {
+ pub fn from_inner(py: Python, dm: DirstateMap) -> PyResult<Self> {
+ Self::create_instance(py, dm)
+ }
+
+ fn is_equal_to(&self, py: Python, other: PyObject) -> PyResult<bool> {
+ for item in other.iter(py)? {
+ if !self.dmap(py).non_normal_entries_contains(py, item?)? {
+ return Ok(false);
+ }
+ }
+ Ok(true)
+ }
+}