Mercurial > public > mercurial-scm > hg-stable
view rust/hg-cpython/src/revlog.rs @ 44015:443dc1655923
rust-index: expose a method to retrieve the C index
The code for `shortesthexnodeidprefix` need to access the actual C index. For
now we grant its wish and expose a method to do so. Once we have the nodemap in
Rust, we will be able to implement the same feature from rust and we will be
able to drop this method.
Differential Revision: https://phab.mercurial-scm.org/D7658
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Thu, 12 Dec 2019 03:39:14 +0100 |
parents | c627f1b2f3c3 |
children | 451d22174b5f |
line wrap: on
line source
// revlog.rs // // Copyright 2019 Georges Racinet <georges.racinet@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 crate::cindex; use cpython::{ ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, }; use hg::Revision; use std::cell::RefCell; /// Return a Struct implementing the Graph trait pub(crate) fn pyindex_to_graph(py: Python, index: PyObject) -> PyResult<cindex::Index> { match index.extract::<MixedIndex>(py) { Ok(midx) => Ok(midx.clone_cindex(py)), Err(_) => cindex::Index::new(py, index), } } py_class!(pub class MixedIndex |py| { data cindex: RefCell<cindex::Index>; def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> { Self::create_instance(py, RefCell::new( cindex::Index::new(py, cindex)?)) } /// Compatibility layer used for Python consumers needing access to the C index /// /// Only use case so far is `scmutil.shortesthexnodeidprefix`, /// that may need to build a custom `nodetree`, based on a specified revset. /// With a Rust implementation of the nodemap, we will be able to get rid of /// this, by exposing our own standalone nodemap class, /// ready to accept `MixedIndex`. def get_cindex(&self) -> PyResult<PyObject> { Ok(self.cindex(py).borrow().inner().clone_ref(py)) } // Reforwarded C index API // index_methods (tp_methods). Same ordering as in revlog.c /// return the gca set of the given revs def ancestors(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "ancestors", args, kw) } /// return the heads of the common ancestors of the given revs def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "commonancestorsheads", args, kw) } /// clear the index caches def clearcaches(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "clearcaches", args, kw) } /// get an index entry def get(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "get", args, kw) } /// return `rev` associated with a node or None def get_rev(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "get_rev", args, kw) } /// return True if the node exist in the index def has_node(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "has_node", args, kw) } /// return `rev` associated with a node or raise RevlogError def rev(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "rev", args, kw) } /// compute phases def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "computephasesmapsets", args, kw) } /// reachableroots def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "reachableroots2", args, kw) } /// get head revisions def headrevs(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "headrevs", args, kw) } /// get filtered head revisions def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "headrevsfiltered", args, kw) } /// True if the object is a snapshot def issnapshot(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "issnapshot", args, kw) } /// Gather snapshot data in a cache dict def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "findsnapshots", args, kw) } /// determine revisions with deltas to reconstruct fulltext def deltachain(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "deltachain", args, kw) } /// slice planned chunk read to reach a density threshold def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "slicechunktodensity", args, kw) } /// append an index entry def append(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "append", args, kw) } /// match a potentially ambiguous node ID def partialmatch(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "partialmatch", args, kw) } /// find length of shortest hex nodeid of a binary ID def shortest(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "shortest", args, kw) } /// stats for the index def stats(&self, *args, **kw) -> PyResult<PyObject> { self.call_cindex(py, "stats", args, kw) } // index_sequence_methods and index_mapping_methods. // // Since we call back through the high level Python API, // there's no point making a distinction between index_get // and index_getitem. def __len__(&self) -> PyResult<usize> { self.cindex(py).borrow().inner().len(py) } def __getitem__(&self, key: PyObject) -> PyResult<PyObject> { // this conversion seems needless, but that's actually because // `index_getitem` does not handle conversion from PyLong, // which expressions such as [e for e in index] internally use. // Note that we don't seem to have a direct way to call // PySequence_GetItem (does the job), which would be better for // for performance let key = match key.extract::<Revision>(py) { Ok(rev) => rev.to_py_object(py).into_object(), Err(_) => key, }; self.cindex(py).borrow().inner().get_item(py, key) } def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> { self.cindex(py).borrow().inner().set_item(py, key, value) } def __delitem__(&self, key: PyObject) -> PyResult<()> { self.cindex(py).borrow().inner().del_item(py, key) } def __contains__(&self, item: PyObject) -> PyResult<bool> { // ObjectProtocol does not seem to provide contains(), so // this is an equivalent implementation of the index_contains() // defined in revlog.c let cindex = self.cindex(py).borrow(); match item.extract::<Revision>(py) { Ok(rev) => { Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision) } Err(_) => { cindex.inner().call_method( py, "has_node", PyTuple::new(py, &[item]), None)? .extract(py) } } } }); impl MixedIndex { /// forward a method call to the underlying C index fn call_cindex( &self, py: Python, name: &str, args: &PyTuple, kwargs: Option<&PyDict>, ) -> PyResult<PyObject> { self.cindex(py) .borrow() .inner() .call_method(py, name, args, kwargs) } pub fn clone_cindex(&self, py: Python) -> cindex::Index { self.cindex(py).borrow().clone_ref(py) } } /// Create the module, with __package__ given from parent pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { let dotted_name = &format!("{}.revlog", package); let m = PyModule::new(py, dotted_name)?; m.add(py, "__package__", package)?; m.add(py, "__doc__", "RevLog - Rust implementations")?; m.add_class::<MixedIndex>(py)?; let sys = PyModule::import(py, "sys")?; let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; sys_modules.set_item(py, dotted_name, &m)?; Ok(m) }