D8157: rust-nodemap: use proper Index API instead of using the C API
Closed by commit rHG857cc79247ac: rust-nodemap: use proper Index API instead of using the C API (authored by Alphare). This revision was automatically updated to reflect the committed changes. This revision was not accepted when it landed; it landed in state "Needs Review". REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D8157?vs=20656=20695 CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D8157/new/ REVISION DETAIL https://phab.mercurial-scm.org/D8157 AFFECTED FILES rust/hg-cpython/src/revlog.rs CHANGE DETAILS diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs +++ b/rust/hg-cpython/src/revlog.rs @@ -5,12 +5,20 @@ // 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 crate::{ +cindex, +utils::{node_from_py_bytes, node_from_py_object}, +}; use cpython::{ -exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule, -PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, +exc::{IndexError, ValueError}, +ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject, +PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject, }; -use hg::{nodemap::NodeMapError, NodeError, Revision}; +use hg::{ +nodemap::{NodeMapError, NodeTree}, +revlog::{nodemap::NodeMap, RevlogIndex}, +NodeError, Revision, +}; use std::cell::RefCell; /// Return a Struct implementing the Graph trait @@ -26,6 +34,7 @@ py_class!(pub class MixedIndex |py| { data cindex: RefCell; +data nt: RefCell>; def __new__(_cls, cindex: PyObject) -> PyResult { Self::new(py, cindex) @@ -42,8 +51,99 @@ Ok(self.cindex(py).borrow().inner().clone_ref(py)) } +// Index API involving nodemap, as defined in mercurial/pure/parsers.py +/// Return Revision if found, raises a bare `error.RevlogError` +/// in case of ambiguity, same as C version does +def get_rev(, node: PyBytes) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +let node = node_from_py_bytes(py, )?; +nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e)) +} + +/// same as `get_rev()` but raises a bare `error.RevlogError` if node +/// is not found. +/// +/// No need to repeat `node` in the exception, `mercurial/revlog.py` +/// will catch and rewrap with it +def rev(, node: PyBytes) -> PyResult { +self.get_rev(py, node)?.ok_or_else(|| revlog_error(py)) +} + +/// return True if the node exist in the index +def has_node(, node: PyBytes) -> PyResult { +self.get_rev(py, node).map(|opt| opt.is_some()) +} + +/// find length of shortest hex nodeid of a binary ID +def shortest(, node: PyBytes) -> PyResult { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?) +{ +Ok(Some(l)) => Ok(l), +Ok(None) => Err(revlog_error(py)), +Err(e) => Err(nodemap_error(py, e)), +} +} + +def partialmatch(, node: PyObject) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); + +let node_as_string = if cfg!(feature = "python3-sys") { +node.cast_as::(py)?.to_string(py)?.to_string() +} +else { +let node = node.extract::(py)?; +String::from_utf8_lossy(node.data(py)).to_string() +}; + +nt.find_hex(idx, _as_string) +// TODO make an inner API returning the node directly +.map(|opt| opt.map( +|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes( +.map_err(|e| nodemap_error(py, e)) + +} + +/// append an index entry +def append(, tup: PyTuple) -> PyResult { +if tup.len(py) < 8 { +// this is better than the panic promised by tup.get_item() +return Err( +PyErr::new::(py, "tuple index out of range")) +} +let node_bytes = tup.get_item(py, 7).extract(py)?; +let node = node_from_py_object(py, _bytes)?; + +let mut idx = self.cindex(py).borrow_mut(); +let rev = idx.len() as Revision; + +idx.append(py, tup)?; +self.get_nodetree(py)?.borrow_mut().as_mut().unwrap() +.insert(&*idx, , rev) +.map_err(|e| nodemap_error(py, e))?; +Ok(py.None()) +} + +def __delitem__(, key: PyObject) -> PyResult<()> { +// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]` +
D8157: rust-nodemap: use proper Index API instead of using the C API
Alphare updated this revision to Diff 20656. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D8157?vs=20376=20656 BRANCH default CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D8157/new/ REVISION DETAIL https://phab.mercurial-scm.org/D8157 AFFECTED FILES rust/hg-cpython/src/revlog.rs CHANGE DETAILS diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs +++ b/rust/hg-cpython/src/revlog.rs @@ -5,12 +5,20 @@ // 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 crate::{ +cindex, +utils::{node_from_py_bytes, node_from_py_object}, +}; use cpython::{ -exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule, -PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, +exc::{IndexError, ValueError}, +ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject, +PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject, }; -use hg::{nodemap::NodeMapError, NodeError, Revision}; +use hg::{ +nodemap::{NodeMapError, NodeTree}, +revlog::{nodemap::NodeMap, RevlogIndex}, +NodeError, Revision, +}; use std::cell::RefCell; /// Return a Struct implementing the Graph trait @@ -26,6 +34,7 @@ py_class!(pub class MixedIndex |py| { data cindex: RefCell; +data nt: RefCell>; def __new__(_cls, cindex: PyObject) -> PyResult { Self::new(py, cindex) @@ -42,8 +51,99 @@ Ok(self.cindex(py).borrow().inner().clone_ref(py)) } +// Index API involving nodemap, as defined in mercurial/pure/parsers.py +/// Return Revision if found, raises a bare `error.RevlogError` +/// in case of ambiguity, same as C version does +def get_rev(, node: PyBytes) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +let node = node_from_py_bytes(py, )?; +nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e)) +} + +/// same as `get_rev()` but raises a bare `error.RevlogError` if node +/// is not found. +/// +/// No need to repeat `node` in the exception, `mercurial/revlog.py` +/// will catch and rewrap with it +def rev(, node: PyBytes) -> PyResult { +self.get_rev(py, node)?.ok_or_else(|| revlog_error(py)) +} + +/// return True if the node exist in the index +def has_node(, node: PyBytes) -> PyResult { +self.get_rev(py, node).map(|opt| opt.is_some()) +} + +/// find length of shortest hex nodeid of a binary ID +def shortest(, node: PyBytes) -> PyResult { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?) +{ +Ok(Some(l)) => Ok(l), +Ok(None) => Err(revlog_error(py)), +Err(e) => Err(nodemap_error(py, e)), +} +} + +def partialmatch(, node: PyObject) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); + +let node_as_string = if cfg!(feature = "python3-sys") { +node.cast_as::(py)?.to_string(py)?.to_string() +} +else { +let node = node.extract::(py)?; +String::from_utf8_lossy(node.data(py)).to_string() +}; + +nt.find_hex(idx, _as_string) +// TODO make an inner API returning the node directly +.map(|opt| opt.map( +|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes( +.map_err(|e| nodemap_error(py, e)) + +} + +/// append an index entry +def append(, tup: PyTuple) -> PyResult { +if tup.len(py) < 8 { +// this is better than the panic promised by tup.get_item() +return Err( +PyErr::new::(py, "tuple index out of range")) +} +let node_bytes = tup.get_item(py, 7).extract(py)?; +let node = node_from_py_object(py, _bytes)?; + +let mut idx = self.cindex(py).borrow_mut(); +let rev = idx.len() as Revision; + +idx.append(py, tup)?; +self.get_nodetree(py)?.borrow_mut().as_mut().unwrap() +.insert(&*idx, , rev) +.map_err(|e| nodemap_error(py, e))?; +Ok(py.None()) +} + +def __delitem__(, key: PyObject) -> PyResult<()> { +// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]` +self.cindex(py).borrow().inner().del_item(py, key)?; +let mut opt = self.get_nodetree(py)?.borrow_mut(); +let mut nt = opt.as_mut().unwrap(); +nt.invalidate_all(); +self.fill_nodemap(py, nt)?; +Ok(()) +} +
D8157: rust-nodemap: use proper Index API instead of using the C API
marmoute updated this revision to Diff 20376. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D8157?vs=20332=20376 BRANCH default CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D8157/new/ REVISION DETAIL https://phab.mercurial-scm.org/D8157 AFFECTED FILES rust/hg-cpython/src/revlog.rs CHANGE DETAILS diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs +++ b/rust/hg-cpython/src/revlog.rs @@ -5,12 +5,20 @@ // 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 crate::{ +cindex, +utils::{node_from_py_bytes, node_from_py_object}, +}; use cpython::{ -exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule, -PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, +exc::{IndexError, ValueError}, +ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject, +PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject, }; -use hg::{nodemap::NodeMapError, NodeError, Revision}; +use hg::{ +nodemap::{NodeMapError, NodeTree}, +revlog::{nodemap::NodeMap, RevlogIndex}, +NodeError, Revision, +}; use std::cell::RefCell; /// Return a Struct implementing the Graph trait @@ -26,6 +34,7 @@ py_class!(pub class MixedIndex |py| { data cindex: RefCell; +data nt: RefCell>; def __new__(_cls, cindex: PyObject) -> PyResult { Self::new(py, cindex) @@ -42,8 +51,99 @@ Ok(self.cindex(py).borrow().inner().clone_ref(py)) } +// Index API involving nodemap, as defined in mercurial/pure/parsers.py +/// Return Revision if found, raises a bare `error.RevlogError` +/// in case of ambiguity, same as C version does +def get_rev(, node: PyBytes) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +let node = node_from_py_bytes(py, )?; +nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e)) +} + +/// same as `get_rev()` but raises a bare `error.RevlogError` if node +/// is not found. +/// +/// No need to repeat `node` in the exception, `mercurial/revlog.py` +/// will catch and rewrap with it +def rev(, node: PyBytes) -> PyResult { +self.get_rev(py, node)?.ok_or_else(|| revlog_error(py)) +} + +/// return True if the node exist in the index +def has_node(, node: PyBytes) -> PyResult { +self.get_rev(py, node).map(|opt| opt.is_some()) +} + +/// find length of shortest hex nodeid of a binary ID +def shortest(, node: PyBytes) -> PyResult { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?) +{ +Ok(Some(l)) => Ok(l), +Ok(None) => Err(revlog_error(py)), +Err(e) => Err(nodemap_error(py, e)), +} +} + +def partialmatch(, node: PyObject) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); + +let node_as_string = if cfg!(feature = "python3-sys") { +node.cast_as::(py)?.to_string(py)?.to_string() +} +else { +let node = node.extract::(py)?; +String::from_utf8_lossy(node.data(py)).to_string() +}; + +nt.find_hex(idx, _as_string) +// TODO make an inner API returning the node directly +.map(|opt| opt.map( +|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes( +.map_err(|e| nodemap_error(py, e)) + +} + +/// append an index entry +def append(, tup: PyTuple) -> PyResult { +if tup.len(py) < 8 { +// this is better than the panic promised by tup.get_item() +return Err( +PyErr::new::(py, "tuple index out of range")) +} +let node_bytes = tup.get_item(py, 7).extract(py)?; +let node = node_from_py_object(py, _bytes)?; + +let mut idx = self.cindex(py).borrow_mut(); +let rev = idx.len() as Revision; + +idx.append(py, tup)?; +self.get_nodetree(py)?.borrow_mut().as_mut().unwrap() +.insert(&*idx, , rev) +.map_err(|e| nodemap_error(py, e))?; +Ok(py.None()) +} + +def __delitem__(, key: PyObject) -> PyResult<()> { +// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]` +self.cindex(py).borrow().inner().del_item(py, key)?; +let mut opt = self.get_nodetree(py)?.borrow_mut(); +let mut nt = opt.as_mut().unwrap(); +nt.invalidate_all(); +self.fill_nodemap(py, nt)?; +Ok(()) +} +
D8157: rust-nodemap: use proper Index API instead of using the C API
Alphare created this revision. Herald added subscribers: mercurial-devel, mjpieters. Herald added a reviewer: hg-reviewers. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D8157 AFFECTED FILES rust/hg-cpython/src/revlog.rs CHANGE DETAILS diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs +++ b/rust/hg-cpython/src/revlog.rs @@ -5,12 +5,20 @@ // 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 crate::{ +cindex, +utils::{node_from_py_bytes, node_from_py_object}, +}; use cpython::{ -exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule, -PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, +exc::{IndexError, ValueError}, +ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject, +PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject, }; -use hg::{nodemap::NodeMapError, NodeError, Revision}; +use hg::{ +nodemap::{NodeMapError, NodeTree}, +revlog::{nodemap::NodeMap, RevlogIndex}, +NodeError, Revision, +}; use std::cell::RefCell; /// Return a Struct implementing the Graph trait @@ -26,6 +34,7 @@ py_class!(pub class MixedIndex |py| { data cindex: RefCell; +data nt: RefCell>; def __new__(_cls, cindex: PyObject) -> PyResult { Self::new(py, cindex) @@ -42,8 +51,90 @@ Ok(self.cindex(py).borrow().inner().clone_ref(py)) } +// Index API involving nodemap, as defined in mercurial/pure/parsers.py +/// Return Revision if found, raises a bare `error.RevlogError` +/// in case of ambiguity, same as C version does +def get_rev(, node: PyBytes) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +let node = node_from_py_bytes(py, )?; +nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e)) +} + +/// same as `get_rev()` but raises a bare `error.RevlogError` if node +/// is not found. +/// +/// No need to repeat `node` in the exception, `mercurial/revlog.py` +/// will catch and rewrap with it +def rev(, node: PyBytes) -> PyResult { +self.get_rev(py, node)?.ok_or_else(|| revlog_error(py)) +} + +/// return True if the node exist in the index +def has_node(, node: PyBytes) -> PyResult { +self.get_rev(py, node).map(|opt| opt.is_some()) +} + +/// find length of shortest hex nodeid of a binary ID +def shortest(, node: PyBytes) -> PyResult { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?) +{ +Ok(Some(l)) => Ok(l), +Ok(None) => Err(revlog_error(py)), +Err(e) => Err(nodemap_error(py, e)), +} +} + +// TODO in py3, I suppose we get PyBytes, actually +def partialmatch(, node: PyString) -> PyResult> { +let opt = self.get_nodetree(py)?.borrow(); +let nt = opt.as_ref().unwrap(); +let idx = &*self.cindex(py).borrow(); +nt.find_hex(idx, _string(py)?) +// TODO make an inner API returning the node directly +.map(|opt| opt.map( +|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes( +.map_err(|e| nodemap_error(py, e)) +} + +/// append an index entry +def append(, tup: PyTuple) -> PyResult { +if tup.len(py) < 8 { +// this is better than the panic promised by tup.get_item() +return Err( +PyErr::new::(py, "tuple index out of range")) +} +let node_bytes = tup.get_item(py, 7).extract(py)?; +let node = node_from_py_object(py, _bytes)?; + +let mut idx = self.cindex(py).borrow_mut(); +let rev = idx.len() as Revision; + +idx.append(py, tup)?; +self.get_nodetree(py)?.borrow_mut().as_mut().unwrap() +.insert(&*idx, , rev) +.map_err(|e| nodemap_error(py, e))?; +Ok(py.None()) +} + +def __delitem__(, key: PyObject) -> PyResult<()> { +// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]` +self.cindex(py).borrow().inner().del_item(py, key)?; +let mut opt = self.get_nodetree(py)?.borrow_mut(); +let mut nt = opt.as_mut().unwrap(); +nt.invalidate_all(); +self.fill_nodemap(py, nt)?; +Ok(()) +} + +// // Reforwarded C index API +// // index_methods (tp_methods). Same ordering as in revlog.c @@ -67,21 +158,6 @@ self.call_cindex(py, "get", args, kw) } -/// return `rev` associated with a node or None -def get_rev(, *args, **kw) -> PyResult { -