rust-pyo3: new module for conversions of HgPath and friends
Same as `PyRevision`, the `PyHgPathRef` new-type wrapper is not
a Python type, but it implements `IntoPyObject`, which will spare
us tedious uses of `PyBytes::new`.
The `paths_py_list` function is the the analog of `revs_py_list`
for paths. There was one similar utility in `hg-cpython`, within
the `dirstate::status` module. We feel it should be in a more global
location, and have a name consistent with utilities for revisions.
The `paths_pyiter_collect` function is similarly the analog of
`revs_pyiter_collect`.
--- a/rust/hg-pyo3/src/lib.rs Wed Jan 29 14:05:26 2025 +0100
+++ b/rust/hg-pyo3/src/lib.rs Thu Feb 06 11:18:28 2025 +0100
@@ -6,6 +6,7 @@
mod discovery;
mod exceptions;
mod node;
+mod path;
mod revision;
mod revlog;
mod store;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hg-pyo3/src/path.rs Thu Feb 06 11:18:28 2025 +0100
@@ -0,0 +1,67 @@
+// path.rs
+//
+// Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
+// 2025 Georges Racinet <georges.racinet@cloudcrane.io>
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+//! Utilities about `HgPath` and related objects provided by the `hg-core`
+//! package.
+
+use pyo3::prelude::*;
+use pyo3::types::{PyBytes, PyList};
+
+use std::convert::Infallible;
+
+use hg::utils::hg_path::{HgPath, HgPathBuf};
+
+#[allow(dead_code)]
+#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, derive_more::From)]
+pub struct PyHgPathRef<'a>(pub &'a HgPath);
+
+impl<'py> IntoPyObject<'py> for PyHgPathRef<'_> {
+ type Target = PyBytes;
+ type Output = Bound<'py, Self::Target>;
+ type Error = Infallible;
+
+ fn into_pyobject(
+ self,
+ py: Python<'py>,
+ ) -> Result<Self::Output, Self::Error> {
+ Ok(PyBytes::new(py, self.0.as_bytes()))
+ }
+}
+
+#[allow(dead_code)]
+pub fn paths_py_list<I, U>(
+ py: Python<'_>,
+ paths: impl IntoIterator<Item = I, IntoIter = U>,
+) -> PyResult<Py<PyList>>
+where
+ I: AsRef<HgPath>,
+ U: ExactSizeIterator<Item = I>,
+{
+ Ok(PyList::new(
+ py,
+ paths
+ .into_iter()
+ .map(|p| PyBytes::new(py, p.as_ref().as_bytes())),
+ )?
+ .unbind())
+}
+
+#[allow(dead_code)]
+pub fn paths_pyiter_collect<C>(paths: &Bound<'_, PyAny>) -> PyResult<C>
+where
+ C: FromIterator<HgPathBuf>,
+{
+ paths
+ .try_iter()?
+ .map(|p| {
+ let path = p?;
+ Ok(HgPathBuf::from_bytes(
+ path.downcast::<PyBytes>()?.as_bytes(),
+ ))
+ })
+ .collect()
+}