rust/hg-pyo3/src/utils.rs
author Pierre-Yves David <pierre-yves.david@octobus.net>
Tue, 11 Mar 2025 02:29:42 +0100
branchstable
changeset 53042 cdd7bf612c7b
parent 52978 69d40a9778fe
permissions -rw-r--r--
bundle-spec: properly format boolean parameter (issue6960) This was breaking automatic clone bundle generation. This changeset fixes it and add a test to catch it in the future.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     1
use hg::errors::HgError;
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
     2
use hg::revlog::index::Index as CoreIndex;
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     3
use hg::revlog::inner_revlog::RevisionBuffer;
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
     4
use pyo3::buffer::{Element, PyBuffer};
52977
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
     5
use pyo3::exceptions::{
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
     6
    PyIOError, PyKeyboardInterrupt, PyRuntimeError, PyValueError,
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
     7
};
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     8
use pyo3::types::{PyBytes, PyDict};
52977
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
     9
use pyo3::{intern, prelude::*};
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    10
use pyo3_sharedref::SharedByPyObject;
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
    11
use stable_deref_trait::StableDeref;
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
    12
52977
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
    13
use crate::exceptions::FallbackError;
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    14
use crate::revlog::{InnerRevlog, PySharedIndex};
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    15
52407
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    16
/// Create the module, with `__package__` given from parent
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    17
///
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    18
/// According to PyO3 documentation, which links to
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    19
/// <https://github.com/PyO3/pyo3/issues/1517>, the same convoluted
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    20
/// write to sys.modules has to be made as with the `cpython` crate.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    21
pub(crate) fn new_submodule<'py>(
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    22
    py: Python<'py>,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    23
    package_name: &str,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    24
    name: &str,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    25
) -> PyResult<Bound<'py, PyModule>> {
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    26
    let dotted_name = &format!("{}.{}", package_name, name);
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    27
    let m = PyModule::new(py, name)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    28
    m.add("__package__", package_name)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    29
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    30
    let sys = PyModule::import(py, "sys")?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    31
    // according to the doc, we could make a static PyString out of
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    32
    // "modules" with the `intern!` macro, but this is used only at
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    33
    // registration so it may not be worth the effort.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    34
    let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.extract()?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    35
    sys_modules.set_item(dotted_name, &m)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    36
    // Example C code (see pyexpat.c and import.c) will "give away the
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    37
    // reference", but we won't because it will be consumed once the
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    38
    // Rust PyObject is dropped.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    39
    Ok(m)
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    40
}
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
    41
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    42
/// Retrieve the shared index wrapper (which contains the core index)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    43
/// from the Python index proxy.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    44
pub fn py_rust_index_to_graph(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    45
    index_proxy: &Bound<'_, PyAny>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    46
) -> PyResult<SharedByPyObject<PySharedIndex>> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    47
    let py_irl = index_proxy.getattr("inner")?;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    48
    let py_irl_ref = py_irl.downcast::<InnerRevlog>()?.borrow();
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    49
    let shareable_irl = &py_irl_ref.irl;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    50
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    51
    // Safety: the owner is the actual one and we do not leak any
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    52
    // internal reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    53
    let index =
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    54
        unsafe { shareable_irl.share_map(&py_irl, |irl| (&irl.index).into()) };
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    55
    Ok(index)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    56
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    57
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    58
/// Error propagation for an [`SharedByPyObject`] wrapping a [`Result`]
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    59
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    60
/// It would be nice for [`SharedByPyObject`] to provide this directly as
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    61
/// a variant of the `map` method with a signature such as:
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    62
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    63
/// ```
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    64
///   unsafe fn map_or_err(&self,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    65
///                        py: Python,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    66
///                        f: impl FnOnce(T) -> Result(U, E),
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    67
///                        convert_err: impl FnOnce(E) -> PyErr)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    68
/// ```
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    69
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    70
/// This would spare users of the `pyo3` crate the additional `unsafe` deref
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    71
/// to inspect the error and return it outside `SharedByPyObject`, and the
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    72
/// subsequent unwrapping that this function performs.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    73
pub(crate) fn py_shared_or_map_err<T, E: std::fmt::Debug + Copy>(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    74
    py: Python,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    75
    leaked: SharedByPyObject<Result<T, E>>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    76
    convert_err: impl FnOnce(E) -> PyErr,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    77
) -> PyResult<SharedByPyObject<T>> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    78
    // Safety: we don't leak the "faked" reference out of `SharedByPyObject`
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    79
    if let Err(e) = *unsafe { leaked.try_borrow(py)? } {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    80
        return Err(convert_err(e));
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    81
    }
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    82
    // Safety: we don't leak the "faked" reference out of `SharedByPyObject`
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    83
    Ok(unsafe {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    84
        leaked.map(py, |res| {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    85
            res.expect("Error case should have already be treated")
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    86
        })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    87
    })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    88
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    89
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    90
/// Full extraction of the proxy index object as received in PyO3 to a
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    91
/// [`CoreIndex`] reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    92
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    93
/// # Safety
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    94
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    95
/// The invariants to maintain are those of the underlying
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    96
/// [`SharedByPyObject::try_borrow`]: the caller must not leak the inner
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    97
/// reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    98
pub(crate) unsafe fn proxy_index_extract<'py>(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    99
    index_proxy: &Bound<'py, PyAny>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   100
) -> PyResult<&'py CoreIndex> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   101
    let py_shared = py_rust_index_to_graph(index_proxy)?;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   102
    let py_shared = &*unsafe { py_shared.try_borrow(index_proxy.py())? };
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   103
    Ok(unsafe { py_shared.static_inner() })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   104
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   105
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   106
/// Type shortcut for the kind of bytes slice trait objects that are used in
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   107
/// particular for mmap data
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   108
type BoxedBytesSlice =
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   109
    Box<dyn std::ops::Deref<Target = [u8]> + Send + Sync + 'static>;
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   110
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   111
/// Take a Python object backed by a Python buffer, and return the underlying
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   112
/// [`PyBuffer`] along with the Rust slice into said buffer.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   113
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   114
/// The caller needs to make sure that the Python buffer is not freed before
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   115
/// the slice, otherwise we'd get a dangling pointer once the incoming
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   116
/// object is freed from Python side. This can be achieved by storing it a
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   117
/// Python object.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   118
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   119
/// The typical use case is to extract mmap data to make it useable in the
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   120
/// constructs from the `hg` crate.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   121
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   122
/// # Safety
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   123
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   124
/// The caller must make sure that the incoming Python object is kept around
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   125
/// for at least as long as the returned [`BoxedBytesSlice`].
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   126
// TODO in PyO3, we already get a reference with two lifetimes, and we
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   127
// could even take a `Borrowed<'a, 'py, T>`.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   128
// So perhaps we could tie everything together with a lifetime so that is
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   129
// is, after all, safe, and this could be called something like `share_buffer`.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   130
#[deny(unsafe_op_in_unsafe_fn)]
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   131
pub unsafe fn take_buffer_with_slice(
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   132
    data: &Bound<'_, PyAny>,
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   133
) -> PyResult<(PyBuffer<u8>, BoxedBytesSlice)> {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   134
    let buf = PyBuffer::<u8>::get(data)?;
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   135
    let len = buf.item_count();
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   136
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   137
    // Build a slice from the buffer data
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   138
    let cbuf = buf.buf_ptr();
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   139
    let bytes = if std::mem::size_of::<u8>() == buf.item_size()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   140
        && buf.is_c_contiguous()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   141
        && u8::is_compatible_format(buf.format())
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   142
        && buf.dimensions() == 1
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   143
        && buf.readonly()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   144
    {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   145
        unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   146
    } else {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   147
        return Err(PyValueError::new_err(
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   148
            "buffer has an invalid memory representation",
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   149
        ));
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   150
    };
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   151
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   152
    Ok((buf, Box::new(bytes)))
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   153
}
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   154
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   155
/// Takes an initialization function `init` which writes bytes to a
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   156
/// Python-backed buffer, to save on a (potentially large) memory allocation
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   157
/// and copy. If `init` fails to write the full expected length `len`, an error
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   158
/// is raised.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   159
pub fn with_pybytes_buffer<F>(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   160
    py: Python,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   161
    len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   162
    init: F,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   163
) -> Result<Py<PyBytes>, hg::revlog::RevlogError>
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   164
where
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   165
    F: FnOnce(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   166
        &mut dyn RevisionBuffer<Target = Py<PyBytes>>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   167
    ) -> Result<(), hg::revlog::RevlogError>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   168
{
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   169
    // Largely inspired by code in PyO3
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   170
    // https://pyo3.rs/main/doc/pyo3/types/struct.pybytes#method.new_bound_with
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   171
    unsafe {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   172
        let pyptr = pyo3::ffi::PyBytes_FromStringAndSize(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   173
            std::ptr::null(),
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   174
            len as pyo3::ffi::Py_ssize_t,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   175
        );
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   176
        let pybytes = Bound::from_owned_ptr_or_err(py, pyptr)
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   177
            .map_err(|e| HgError::abort_simple(e.to_string()))?
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   178
            .downcast_into_unchecked();
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   179
        let buffer: *mut u8 = pyo3::ffi::PyBytes_AsString(pyptr).cast();
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   180
        debug_assert!(!buffer.is_null());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   181
        let mut rev_buf = PyRevisionBuffer::new(pybytes.unbind(), buffer, len);
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   182
        // Initialise the bytestring in init
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   183
        // If init returns an Err, the buffer is deallocated by `pybytes`
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   184
        init(&mut rev_buf).map(|_| rev_buf.finish())
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   185
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   186
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   187
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   188
/// Safe abstraction over a `PyBytes` together with the `&[u8]` slice
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   189
/// that borrows it. Implements `Deref<Target = [u8]>`.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   190
///
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   191
/// Calling `PyBytes::data` requires a GIL marker but we want to access the
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   192
/// data in a thread that (ideally) does not need to acquire the GIL.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   193
/// This type allows separating the call an the use.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   194
///
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   195
/// It also enables using a (wrapped) `PyBytes` in GIL-unaware generic code.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   196
pub struct PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   197
    #[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   198
    keep_alive: Py<PyBytes>,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   199
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   200
    /// Borrows the buffer inside `self.keep_alive`,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   201
    /// but the borrow-checker cannot express self-referential structs.
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   202
    data: &'static [u8],
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   203
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   204
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   205
impl PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   206
    pub fn new(py: Python, bytes: Py<PyBytes>) -> Self {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   207
        let as_raw: *const [u8] = bytes.as_bytes(py);
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   208
        Self {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   209
            // Safety: the raw pointer is valid as long as the PyBytes is still
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   210
            // alive, and the objecs owns it.
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   211
            data: unsafe { &*as_raw },
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   212
            keep_alive: bytes,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   213
        }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   214
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   215
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   216
    #[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   217
    pub fn unwrap(self) -> Py<PyBytes> {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   218
        self.keep_alive
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   219
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   220
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   221
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   222
impl std::ops::Deref for PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   223
    type Target = [u8];
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   224
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   225
    fn deref(&self) -> &[u8] {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   226
        self.data
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   227
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   228
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   229
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   230
unsafe impl StableDeref for PyBytesDeref {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   231
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   232
fn require_send<T: Send>() {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   233
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   234
#[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   235
fn static_assert_pybytes_is_send() {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   236
    #[allow(clippy::no_effect)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   237
    require_send::<Py<PyBytes>>;
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   238
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   239
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   240
// Safety: `[Py<PyBytes>]` is Send. Raw pointers are not by default,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   241
// but here sending one to another thread is fine since we ensure it stays
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   242
// valid.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   243
unsafe impl Send for PyBytesDeref {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   244
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   245
/// Wrapper around a Python-provided buffer into which the revision contents
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   246
/// will be written. Done for speed in order to save a large allocation + copy.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   247
struct PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   248
    py_bytes: Py<PyBytes>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   249
    _buf: *mut u8,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   250
    len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   251
    current_buf: *mut u8,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   252
    current_len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   253
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   254
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   255
impl PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   256
    /// # Safety
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   257
    ///
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   258
    /// `buf` should be the start of the allocated bytes of `bytes`, and `len`
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   259
    /// exactly the length of said allocated bytes.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   260
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   261
    unsafe fn new(bytes: Py<PyBytes>, buf: *mut u8, len: usize) -> Self {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   262
        Self {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   263
            py_bytes: bytes,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   264
            _buf: buf,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   265
            len,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   266
            current_len: 0,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   267
            current_buf: buf,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   268
        }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   269
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   270
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   271
    /// Number of bytes that have been copied to. Will be different to the
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   272
    /// total allocated length of the buffer unless the revision is done being
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   273
    /// written.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   274
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   275
    fn current_len(&self) -> usize {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   276
        self.current_len
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   277
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   278
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   279
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   280
impl RevisionBuffer for PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   281
    type Target = Py<PyBytes>;
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   282
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   283
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   284
    fn extend_from_slice(&mut self, slice: &[u8]) {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   285
        assert!(self.current_len + slice.len() <= self.len);
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   286
        unsafe {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   287
            // We cannot use `copy_from_nonoverlapping` since it's *possible*
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   288
            // to create a slice from the same Python memory region using
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   289
            // [`PyBytesDeref`]. Probable that LLVM has an optimization anyway?
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   290
            self.current_buf.copy_from(slice.as_ptr(), slice.len());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   291
            self.current_buf = self.current_buf.add(slice.len());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   292
        }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   293
        self.current_len += slice.len()
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   294
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   295
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   296
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   297
    fn finish(self) -> Self::Target {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   298
        // catch unzeroed bytes before it becomes undefined behavior
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   299
        assert_eq!(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   300
            self.current_len(),
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   301
            self.len,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   302
            "not enough bytes read for revision"
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   303
        );
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   304
        self.py_bytes
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   305
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   306
}
52977
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   307
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   308
/// Extension trait to help with generic error conversions from hg-core to
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   309
/// Python.
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   310
pub(crate) trait HgPyErrExt<T> {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   311
    fn into_pyerr(self, py: Python) -> PyResult<T>;
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   312
}
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   313
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   314
impl<T, E> HgPyErrExt<T> for Result<T, E>
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   315
where
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   316
    HgError: From<E>,
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   317
{
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   318
    fn into_pyerr(self, py: Python) -> PyResult<T> {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   319
        self.map_err(|e| match e.into() {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   320
            err @ HgError::IoError { .. } => {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   321
                PyIOError::new_err(err.to_string())
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   322
            }
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   323
            HgError::UnsupportedFeature(e) => {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   324
                FallbackError::new_err(e.to_string())
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   325
            }
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   326
            HgError::RaceDetected(_) => {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   327
                unreachable!("must not surface to the user")
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   328
            }
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   329
            HgError::Path(path_error) => {
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   330
                let msg = PyBytes::new(py, path_error.to_string().as_bytes());
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   331
                let cls = py
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   332
                    .import(intern!(py, "mercurial.error"))
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   333
                    .and_then(|m| m.getattr(intern!(py, "InputError")))
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   334
                    .expect("failed to import InputError");
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   335
                PyErr::from_value(
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   336
                    cls.call1((msg,))
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   337
                        .expect("initializing an InputError failed"),
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   338
                )
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   339
            }
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   340
            HgError::InterruptReceived => PyKeyboardInterrupt::new_err(()),
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   341
            e => PyRuntimeError::new_err(e.to_string()),
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   342
        })
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   343
    }
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   344
}
0c7ac026ed63 pyo3: add a generic error conversion extension trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52976
diff changeset
   345
52978
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   346
/// Wrap a call to `func` so that Python's `SIGINT` handler is first stored,
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   347
/// then restored after the call to `func` and finally raised if
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   348
/// `func` returns a [`HgError::InterruptReceived`].
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   349
///
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   350
/// We cannot use [`Python::check_signals`] because it only works from the main
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   351
/// thread of the main interpreter. To that end, long-running Rust functions
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   352
/// need to cooperate by listening to their own `SIGINT` signal and return
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   353
/// the appropriate error on catching that signal: this is especially helpful
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   354
/// in multithreaded operations.
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   355
pub fn with_sigint_wrapper<R>(
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   356
    py: Python,
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   357
    func: impl Fn() -> Result<R, HgError>,
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   358
) -> PyResult<Result<R, HgError>> {
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   359
    let signal_py_mod = py.import(intern!(py, "signal"))?;
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   360
    let sigint_py_const = signal_py_mod.getattr(intern!(py, "SIGINT"))?;
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   361
    let old_handler = signal_py_mod
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   362
        .call_method1(intern!(py, "getsignal"), (sigint_py_const.clone(),))?;
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   363
    let res = func();
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   364
    // Reset the old signal handler in Python because we may have changed it
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   365
    signal_py_mod.call_method1(
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   366
        intern!(py, "signal"),
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   367
        (sigint_py_const.clone(), old_handler),
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   368
    )?;
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   369
    if let Err(HgError::InterruptReceived) = res {
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   370
        // Trigger the signal in Python
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   371
        signal_py_mod
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   372
            .call_method1(intern!(py, "raise_signal"), (sigint_py_const,))?;
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   373
    }
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   374
    Ok(res)
69d40a9778fe pyo3: add a util to handle SIGINT from a long-running Rust function
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52977
diff changeset
   375
}