annotate rust/hg-pyo3/src/utils.rs @ 53042:cdd7bf612c7b stable tip

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.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 11 Mar 2025 02:29:42 +0100
parents 69d40a9778fe
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
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 }