##// END OF EJS Templates
copies-rust: use the entry API to overwrite deleted entry...
copies-rust: use the entry API to overwrite deleted entry This is more efficient, more idiomatic and more compact. The main motivation for this change is to cleanup that area before start to do "overwrite" tracking. Such tracking will ultimately help to avoid costly is_ancestors call when merging changeset. Differential Revision: https://phab.mercurial-scm.org/D9494

File last commit:

r46764:294d5aca default
r46767:e166e8a0 default
Show More
copy_tracing.rs
148 lines | 4.9 KiB | application/rls-services+xml | RustLexer
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 use cpython::ObjectProtocol;
use cpython::PyBool;
use cpython::PyBytes;
use cpython::PyDict;
use cpython::PyList;
use cpython::PyModule;
use cpython::PyObject;
use cpython::PyResult;
use cpython::PyTuple;
use cpython::Python;
use hg::copy_tracing::combine_changeset_copies;
use hg::copy_tracing::ChangedFiles;
copies-rust: parse the changed-file sidedata directly in rust...
r46674 use hg::copy_tracing::DataHolder;
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 use hg::copy_tracing::RevInfo;
copies-rust: parse the changed-file sidedata directly in rust...
r46674 use hg::copy_tracing::RevInfoMaker;
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 use hg::Revision;
/// Combines copies information contained into revision `revs` to build a copy
/// map.
///
/// See mercurial/copies.py for details
pub fn combine_changeset_copies_wrapper(
py: Python,
revs: PyList,
copies: iterate over children directly (instead of parents)...
r46764 children_count: PyDict,
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 target_rev: Revision,
rev_info: PyObject,
is_ancestor: PyObject,
) -> PyResult<PyDict> {
let revs: PyResult<_> =
revs.iter(py).map(|r| Ok(r.extract(py)?)).collect();
// Wrap the `is_ancestor` python callback as a Rust closure
//
// No errors are expected from the Python side, and they will should only
// happens in case of programing error or severe data corruption. Such
// errors will raise panic and the rust-cpython harness will turn them into
// Python exception.
let is_ancestor_wrap = |anc: Revision, desc: Revision| -> bool {
is_ancestor
.call(py, (anc, desc), None)
.expect(
"rust-copy-tracing: python call to `is_ancestor` \
failed",
)
.cast_into::<PyBool>(py)
.expect(
"rust-copy-tracing: python call to `is_ancestor` \
returned unexpected non-Bool value",
)
.is_true()
};
// Wrap the `rev_info_maker` python callback as a Rust closure
//
// No errors are expected from the Python side, and they will should only
// happens in case of programing error or severe data corruption. Such
// errors will raise panic and the rust-cpython harness will turn them into
// Python exception.
copies-rust: parse the changed-file sidedata directly in rust...
r46674 let rev_info_maker: RevInfoMaker<PyBytes> =
Box::new(|rev: Revision, d: &mut DataHolder<PyBytes>| -> RevInfo {
let res: PyTuple = rev_info
.call(py, (rev,), None)
.expect("rust-copy-tracing: python call to `rev_info` failed")
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 .cast_into(py)
.expect(
copies-rust: parse the changed-file sidedata directly in rust...
r46674 "rust-copy_tracing: python call to `rev_info` returned \
unexpected non-Tuple value",
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 );
copies-rust: parse the changed-file sidedata directly in rust...
r46674 let p1 = res.get_item(py, 0).extract(py).expect(
"rust-copy-tracing: rev_info return is invalid, first item \
is a not a revision",
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 );
copies-rust: parse the changed-file sidedata directly in rust...
r46674 let p2 = res.get_item(py, 1).extract(py).expect(
"rust-copy-tracing: rev_info return is invalid, first item \
is a not a revision",
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 );
copies-rust: parse the changed-file sidedata directly in rust...
r46674 let files = match res.get_item(py, 2).extract::<PyBytes>(py) {
Ok(raw) => {
// Give responsability for the raw bytes lifetime to
// hg-core
d.data = Some(raw);
let addrs = d.data.as_ref().expect(
"rust-copy-tracing: failed to get a reference to the \
raw bytes for copy data").data(py);
ChangedFiles::new(addrs)
}
// value was presumably None, meaning they was no copy data.
Err(_) => ChangedFiles::new_empty(),
};
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557
copies-rust: parse the changed-file sidedata directly in rust...
r46674 (p1, p2, files)
});
copies: iterate over children directly (instead of parents)...
r46764 let children_count: PyResult<_> = children_count
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 .items(py)
.iter()
copies: iterate over children directly (instead of parents)...
r46764 .map(|(k, v)| Ok((k.extract(py)?, v.extract(py)?)))
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 .collect();
let res = combine_changeset_copies(
revs?,
copies: iterate over children directly (instead of parents)...
r46764 children_count?,
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 target_rev,
copies-rust: parse the changed-file sidedata directly in rust...
r46674 rev_info_maker,
copies: introduce the hg-cpython wrapper for `combine_changeset_copies`...
r46557 &is_ancestor_wrap,
);
let out = PyDict::new(py);
for (dest, source) in res.into_iter() {
out.set_item(
py,
PyBytes::new(py, &dest.into_vec()),
PyBytes::new(py, &source.into_vec()),
)?;
}
Ok(out)
}
/// Create the module, with `__package__` given from parent
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
let dotted_name = &format!("{}.copy_tracing", package);
let m = PyModule::new(py, dotted_name)?;
m.add(py, "__package__", package)?;
m.add(py, "__doc__", "Copy tracing - Rust implementation")?;
m.add(
py,
"combine_changeset_copies",
py_fn!(
py,
combine_changeset_copies_wrapper(
revs: PyList,
children: PyDict,
target_rev: Revision,
rev_info: PyObject,
is_ancestor: PyObject
)
),
)?;
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)
}