view rust/hg-cpython/src/dagops.rs @ 51199:16d477bb0078

rust-index: return variables systematic naming convention To help knowing at a glance when a method is ready, making us more comofortable when we are close to the final removal of scaffolding, we introduce the systematic variable names `rust_res` and `c_res`. The goal of this series is to always return the formet. We take again the case of `pack_header` as example. Our personal opinion is to usually avoid such poor semantics as `res`, but usually accept it when it close to the actual return, which will be the case in most methods of this series. Also, the name can simply be dropped when we remove the scaffolding. To follow on the example, the body of `pack_header()` should become this in the final version: ``` let index = self.index(py).borrow(); let packed = index.pack_header(args.get_item(py, 0).extract(py)?); Ok(PyBytes::new(py, &packed).into_object()); ``` in these cases it is close to the actual return and will be removed at the end entirely.
author Georges Racinet <georges.racinet@octobus.net>
date Sat, 30 Sep 2023 16:15:56 +0200
parents 4c5f6e95df84
children 578c049f0408
line wrap: on
line source

// dagops.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.

//! Bindings for the `hg::dagops` module provided by the
//! `hg-core` package.
//!
//! From Python, this will be seen as `mercurial.rustext.dagop`
use crate::PyRevision;
use crate::{conversion::rev_pyiter_collect, exceptions::GraphError};
use cpython::{PyDict, PyModule, PyObject, PyResult, Python};
use hg::dagops;
use hg::Revision;
use std::collections::HashSet;
use vcsgraph::ancestors::node_rank;
use vcsgraph::graph::{Parents, Rank};

use crate::revlog::pyindex_to_graph;

/// Using the the `index`, return heads out of any Python iterable of Revisions
///
/// This is the Rust counterpart for `mercurial.dagop.headrevs`
pub fn headrevs(
    py: Python,
    index: PyObject,
    revs: PyObject,
) -> PyResult<HashSet<PyRevision>> {
    let index = pyindex_to_graph(py, index)?;
    let mut as_set: HashSet<Revision> = rev_pyiter_collect(py, &revs, &index)?;
    dagops::retain_heads(&index, &mut as_set)
        .map_err(|e| GraphError::pynew(py, e))?;
    Ok(as_set.into_iter().map(Into::into).collect())
}

/// Computes the rank, i.e. the number of ancestors including itself,
/// of a node represented by its parents.
pub fn rank(
    py: Python,
    index: PyObject,
    p1r: PyRevision,
    p2r: PyRevision,
) -> PyResult<Rank> {
    node_rank(&pyindex_to_graph(py, index)?, &Parents([p1r.0, p2r.0]))
        .map_err(|e| GraphError::pynew_from_vcsgraph(py, e))
}

/// Create the module, with `__package__` given from parent
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
    let dotted_name = &format!("{}.dagop", package);
    let m = PyModule::new(py, dotted_name)?;
    m.add(py, "__package__", package)?;
    m.add(py, "__doc__", "DAG operations - Rust implementation")?;
    m.add(
        py,
        "headrevs",
        py_fn!(py, headrevs(index: PyObject, revs: PyObject)),
    )?;
    m.add(
        py,
        "rank",
        py_fn!(py, rank(index: PyObject, p1r: PyRevision, p2r: PyRevision)),
    )?;

    let sys = PyModule::import(py, "sys")?;
    let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
    sys_modules.set_item(py, dotted_name, &m)?;
    // Example C code (see pyexpat.c and import.c) will "give away the
    // reference", but we won't because it will be consumed once the
    // Rust PyObject is dropped.
    Ok(m)
}