rust-pyo3-dirsate: DirstateMap definition and constructors
authorGeorges Racinet <georges.racinet@cloudcrane.io>
Wed, 29 Jan 2025 14:05:26 +0100
changeset 52857 e7b825893e1b
parent 52856 e2d2961b8383
child 52858 c60f69556924
rust-pyo3-dirsate: DirstateMap definition and constructors With rust-cpython, using `Option<T>` in the Rust signature would translate automatically into a Python keyword argument, leading to unpleasantness on the Rust side in some cases (not here, though). with PyO3, though the signature can be specified explicitly (positional in this case) and there is even a warning that the implicit keywords style is deprecated.
rust/hg-pyo3/src/dirstate.rs
rust/hg-pyo3/src/dirstate/dirstate_map.rs
rust/hg-pyo3/src/exceptions.rs
--- a/rust/hg-pyo3/src/dirstate.rs	Thu Feb 06 11:40:38 2025 +0100
+++ b/rust/hg-pyo3/src/dirstate.rs	Wed Jan 29 14:05:26 2025 +0100
@@ -15,7 +15,7 @@
 mod item;
 use item::DirstateItem;
 mod dirstate_map;
-use dirstate_map::DirstateIdentity;
+use dirstate_map::{DirstateIdentity, DirstateMap};
 
 pub fn init_module<'py>(
     py: Python<'py>,
@@ -26,5 +26,6 @@
     m.add("FallbackError", py.get_type::<exceptions::FallbackError>())?;
     m.add_class::<DirstateIdentity>()?;
     m.add_class::<DirstateItem>()?;
+    m.add_class::<DirstateMap>()?;
     Ok(m)
 }
--- a/rust/hg-pyo3/src/dirstate/dirstate_map.rs	Thu Feb 06 11:40:38 2025 +0100
+++ b/rust/hg-pyo3/src/dirstate/dirstate_map.rs	Wed Jan 29 14:05:26 2025 +0100
@@ -9,8 +9,77 @@
 //! `hg-core` package.
 
 use pyo3::prelude::*;
+use pyo3::types::{PyBytes, PyBytesMethods, PyTuple};
+use pyo3_sharedref::PyShareable;
 
-use hg::dirstate::dirstate_map::DirstateIdentity as CoreDirstateIdentity;
+use hg::dirstate::{
+    dirstate_map::DirstateIdentity as CoreDirstateIdentity,
+    owning::OwningDirstateMap,
+};
+
+use crate::{exceptions::dirstate_error, node::PyNode, utils::PyBytesDeref};
+
+#[pyclass]
+pub struct DirstateMap {
+    #[allow(dead_code)]
+    inner: PyShareable<OwningDirstateMap>,
+}
+
+#[pymethods]
+impl DirstateMap {
+    #[staticmethod]
+    #[pyo3(signature = (on_disk, identity))]
+    /// Returns a `(dirstate_map, parents)` tuple
+    ///
+    /// The Python call site is using the positional argument style, hence
+    /// despite the fact that `identity` can be `None`, we specify the
+    /// matching signature.
+    fn new_v1(
+        py: Python,
+        on_disk: Py<PyBytes>,
+        identity: Option<&Bound<'_, DirstateIdentity>>,
+    ) -> PyResult<Py<PyTuple>> {
+        let on_disk = PyBytesDeref::new(py, on_disk);
+        let (map, parents) = OwningDirstateMap::new_v1(
+            on_disk,
+            identity.map(|i| i.borrow().inner),
+        )
+        .map_err(dirstate_error)?;
+        let map = Self { inner: map.into() };
+        let parents = (PyNode(parents.p1), PyNode(parents.p2));
+        Ok((map, parents).into_pyobject(py)?.into())
+    }
+
+    #[staticmethod]
+    #[pyo3(signature = (on_disk, data_size, tree_metadata, uuid, identity))]
+    fn new_v2(
+        py: Python,
+        on_disk: Py<PyBytes>,
+        data_size: usize,
+        tree_metadata: &Bound<'_, PyBytes>,
+        uuid: &Bound<'_, PyBytes>,
+        identity: Option<&Bound<'_, DirstateIdentity>>,
+    ) -> PyResult<Self> {
+        Ok(Self {
+            inner: OwningDirstateMap::new_v2(
+                PyBytesDeref::new(py, on_disk),
+                data_size,
+                tree_metadata.as_bytes(),
+                uuid.as_bytes().to_owned(),
+                identity.map(|i| i.borrow().inner),
+            )
+            .map_err(dirstate_error)?
+            .into(),
+        })
+    }
+
+    #[staticmethod]
+    fn new_empty() -> PyResult<Self> {
+        Ok(Self {
+            inner: OwningDirstateMap::new_empty(vec![], None).into(),
+        })
+    }
+}
 
 #[pyclass]
 pub struct DirstateIdentity {
--- a/rust/hg-pyo3/src/exceptions.rs	Thu Feb 06 11:40:38 2025 +0100
+++ b/rust/hg-pyo3/src/exceptions.rs	Wed Jan 29 14:05:26 2025 +0100
@@ -88,7 +88,6 @@
     PyValueError::new_err("parent out of range")
 }
 
-#[allow(dead_code)]
 pub fn dirstate_error(err: DirstateError) -> PyErr {
     PyOSError::new_err(format!("Dirstate error: {:?}", err))
 }