Mercurial > public > mercurial-scm > hg-stable
changeset 52982:0c7ac026ed63
pyo3: add a generic error conversion extension trait
This is going to be useful in more high-level modules like the upcoming
`update` module.
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Tue, 18 Feb 2025 11:39:17 +0100 |
parents | d934d730c6c2 |
children | 69d40a9778fe |
files | rust/hg-pyo3/src/utils.rs |
diffstat | 1 files changed, 44 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-pyo3/src/utils.rs Tue Feb 18 11:33:20 2025 +0100 +++ b/rust/hg-pyo3/src/utils.rs Tue Feb 18 11:39:17 2025 +0100 @@ -2,12 +2,15 @@ use hg::revlog::index::Index as CoreIndex; use hg::revlog::inner_revlog::RevisionBuffer; use pyo3::buffer::{Element, PyBuffer}; -use pyo3::exceptions::PyValueError; -use pyo3::prelude::*; +use pyo3::exceptions::{ + PyIOError, PyKeyboardInterrupt, PyRuntimeError, PyValueError, +}; use pyo3::types::{PyBytes, PyDict}; +use pyo3::{intern, prelude::*}; use pyo3_sharedref::SharedByPyObject; use stable_deref_trait::StableDeref; +use crate::exceptions::FallbackError; use crate::revlog::{InnerRevlog, PySharedIndex}; /// Create the module, with `__package__` given from parent @@ -301,3 +304,42 @@ self.py_bytes } } + +/// Extension trait to help with generic error conversions from hg-core to +/// Python. +pub(crate) trait HgPyErrExt<T> { + fn into_pyerr(self, py: Python) -> PyResult<T>; +} + +impl<T, E> HgPyErrExt<T> for Result<T, E> +where + HgError: From<E>, +{ + fn into_pyerr(self, py: Python) -> PyResult<T> { + self.map_err(|e| match e.into() { + err @ HgError::IoError { .. } => { + PyIOError::new_err(err.to_string()) + } + HgError::UnsupportedFeature(e) => { + FallbackError::new_err(e.to_string()) + } + HgError::RaceDetected(_) => { + unreachable!("must not surface to the user") + } + HgError::Path(path_error) => { + let msg = PyBytes::new(py, path_error.to_string().as_bytes()); + let cls = py + .import(intern!(py, "mercurial.error")) + .and_then(|m| m.getattr(intern!(py, "InputError"))) + .expect("failed to import InputError"); + PyErr::from_value( + cls.call1((msg,)) + .expect("initializing an InputError failed"), + ) + } + HgError::InterruptReceived => PyKeyboardInterrupt::new_err(()), + e => PyRuntimeError::new_err(e.to_string()), + }) + } +} +