##// END OF EJS Templates
rust-revlog: bare minimal NodeTree exposition...
Georges Racinet -
r52142:2966b88d default
parent child Browse files
Show More
@@ -965,6 +965,73 b' impl MixedIndex {'
965 }
965 }
966 }
966 }
967
967
968 py_class!(pub class NodeTree |py| {
969 data nt: RefCell<CoreNodeTree>;
970 data index: RefCell<UnsafePyLeaked<PySharedIndex>>;
971
972 def __new__(_cls, index: PyObject) -> PyResult<NodeTree> {
973 let index = py_rust_index_to_graph(py, index)?;
974 let nt = CoreNodeTree::default(); // in-RAM, fully mutable
975 Self::create_instance(py, RefCell::new(nt), RefCell::new(index))
976 }
977
978 def insert(&self, rev: PyRevision) -> PyResult<PyObject> {
979 let leaked = self.index(py).borrow();
980 let index = &*unsafe { leaked.try_borrow(py)? };
981
982 let rev = UncheckedRevision(rev.0);
983 let rev = index
984 .check_revision(rev)
985 .ok_or_else(|| rev_not_in_index(py, rev))?;
986 if rev == NULL_REVISION {
987 return Err(rev_not_in_index(py, rev.into()))
988 }
989
990 let entry = index.inner.get_entry(rev).unwrap();
991 let mut nt = self.nt(py).borrow_mut();
992 nt.insert(index, entry.hash(), rev).map_err(|e| nodemap_error(py, e))?;
993
994 Ok(py.None())
995 }
996
997 /// Lookup by node hex prefix in the NodeTree, returning revision number.
998 ///
999 /// This is not part of the classical NodeTree API, but is good enough
1000 /// for unit testing, as in `test-rust-revlog.py`.
1001 def prefix_rev_lookup(
1002 &self,
1003 node_prefix: PyBytes
1004 ) -> PyResult<Option<PyRevision>> {
1005 let prefix = NodePrefix::from_hex(node_prefix.data(py))
1006 .map_err(|_| PyErr::new::<ValueError, _>(
1007 py,
1008 format!("Invalid node or prefix {:?}",
1009 node_prefix.as_object()))
1010 )?;
1011
1012 let nt = self.nt(py).borrow();
1013 let leaked = self.index(py).borrow();
1014 let index = &*unsafe { leaked.try_borrow(py)? };
1015
1016 Ok(nt.find_bin(index, prefix)
1017 .map_err(|e| nodemap_error(py, e))?
1018 .map(|r| r.into())
1019 )
1020 }
1021
1022 def shortest(&self, node: PyBytes) -> PyResult<usize> {
1023 let nt = self.nt(py).borrow();
1024 let leaked = self.index(py).borrow();
1025 let idx = &*unsafe { leaked.try_borrow(py)? };
1026 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
1027 {
1028 Ok(Some(l)) => Ok(l),
1029 Ok(None) => Err(revlog_error(py)),
1030 Err(e) => Err(nodemap_error(py, e)),
1031 }
1032 }
1033 });
1034
968 fn revlog_error(py: Python) -> PyErr {
1035 fn revlog_error(py: Python) -> PyErr {
969 match py
1036 match py
970 .import("mercurial.error")
1037 .import("mercurial.error")
@@ -1033,6 +1100,7 b' pub fn init_module(py: Python, package: '
1033 m.add(py, "__doc__", "RevLog - Rust implementations")?;
1100 m.add(py, "__doc__", "RevLog - Rust implementations")?;
1034
1101
1035 m.add_class::<MixedIndex>(py)?;
1102 m.add_class::<MixedIndex>(py)?;
1103 m.add_class::<NodeTree>(py)?;
1036
1104
1037 let sys = PyModule::import(py, "sys")?;
1105 let sys = PyModule::import(py, "sys")?;
1038 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
1106 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
@@ -1,6 +1,8 b''
1 import struct
1 import struct
2 import unittest
2 import unittest
3
3
4 from mercurial.node import hex
5
4 try:
6 try:
5 from mercurial import rustext
7 from mercurial import rustext
6
8
@@ -57,6 +59,35 b' class RustRevlogIndexTest(revlogtesting.'
57 self.assertFalse(LazyAncestors(rustidx, [0], 0, False))
59 self.assertFalse(LazyAncestors(rustidx, [0], 0, False))
58
60
59
61
62 @unittest.skipIf(
63 rustext is None,
64 "rustext module revlog relies on is not available",
65 )
66 class RustRevlogNodeTreeClassTest(revlogtesting.RustRevlogBasedTestBase):
67 def test_standalone_nodetree(self):
68 idx = self.parserustindex()
69 nt = revlog.NodeTree(idx)
70 for i in range(4):
71 nt.insert(i)
72
73 bin_nodes = [entry[7] for entry in idx]
74 hex_nodes = [hex(n) for n in bin_nodes]
75
76 for i, node in enumerate(hex_nodes):
77 self.assertEqual(nt.prefix_rev_lookup(node), i)
78 self.assertEqual(nt.prefix_rev_lookup(node[:5]), i)
79
80 # all 4 revisions in idx (standard data set) have different
81 # first nybbles in their Node IDs,
82 # hence `nt.shortest()` should return 1 for them, except when
83 # the leading nybble is 0 (ambiguity with NULL_NODE)
84 for i, (bin_node, hex_node) in enumerate(zip(bin_nodes, hex_nodes)):
85 shortest = nt.shortest(bin_node)
86 expected = 2 if hex_node[0] == ord('0') else 1
87 self.assertEqual(shortest, expected)
88 self.assertEqual(nt.prefix_rev_lookup(hex_node[:shortest]), i)
89
90
60 if __name__ == '__main__':
91 if __name__ == '__main__':
61 import silenttestrunner
92 import silenttestrunner
62
93
General Comments 0
You need to be logged in to leave comments. Login now