annotate rust/hg-pyo3/src/convert_cpython.rs @ 52556:bd65cb043aa5

rust-pyo3: error propagation for UnsafePyLeaked wrapping a result This `py_leaked_or_map_err` is the PyO3 version of the function of the same name in `hg-cpython/src/ancestors.rs`.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Sat, 07 Dec 2024 18:18:09 +0100
parents 1dd673c1ab3b
children 736551565871
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
1 //! This module takes care of all conversions involving `rusthg` (hg-cpython)
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
2 //! objects in the PyO3 call context.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
3 //!
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
4 //! For source code clarity, we only import (`use`) [`cpython`] traits and not
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
5 //! any of its data objects. We are instead using full qualifiers, such as
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
6 //! `cpython::PyObject`, and believe that the added heaviness is an acceptatble
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
7 //! price to pay to avoid confusion.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
8 //!
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
9 //! Also it, is customary in [`cpython`] to label the GIL lifetime as `'p`,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
10 //! whereas it is `'py` in PyO3 context. We keep both these conventions in
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
11 //! the arguments side of function signatures when they are not simply elided.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
12 use pyo3::exceptions::PyTypeError;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
13 use pyo3::prelude::*;
52555
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
14 use pyo3::{pyclass::boolean_struct::False, PyClass};
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
15
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
16 use cpython::ObjectProtocol;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
17 use cpython::PythonObject;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
18 use lazy_static::lazy_static;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
19
52445
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
20 use hg::revlog::index::Index as CoreIndex;
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
21 use rusthg::revlog::{InnerRevlog, PySharedIndex};
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
22
52555
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
23 /// Marker trait for PyO3 objects with a lifetime representing the acquired GIL
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
24 ///
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
25 /// # Safety
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
26 ///
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
27 /// This trait must not be implemented for objects with lifetimes that
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
28 /// do not imply in PyO3 that the GIL is acquired during the whole lifetime.
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
29 pub unsafe trait WithGIL<'py> {}
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
30
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
31 // Safety: the lifetime on these PyO3 objects all represent the acquired GIL
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
32 unsafe impl<'py> WithGIL<'py> for Python<'py> {}
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
33 unsafe impl<'py, T> WithGIL<'py> for Bound<'py, T> {}
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
34 unsafe impl<'py, T: PyClass> WithGIL<'py> for PyRef<'py, T> {}
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
35 unsafe impl<'py, T: PyClass<Frozen = False>> WithGIL<'py>
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
36 for PyRefMut<'py, T>
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
37 {
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
38 }
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
39
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
40 /// Force cpython's GIL handle with the appropriate lifetime
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
41 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
42 /// In `pyo3`, the fact that we have the GIL is expressed by the lifetime of
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
43 /// the incoming [`Bound`] smart pointer. We therefore simply instantiate
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
44 /// the `cpython` handle and coerce its lifetime by the function signature.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
45 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
46 /// Reacquiring the GIL is also a possible alternative, as the CPython
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
47 /// documentation explicitely states that "recursive calls are allowed"
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
48 /// (we interpret that as saying that acquiring the GIL within a thread that
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
49 /// already has it works) *as long as it is properly released*
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
50 /// reference:
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
51 /// <https://docs.python.org/3.8/c-api/init.html#c.PyGILState_Ensure>
52555
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
52 pub(crate) fn cpython_handle<'py, T: WithGIL<'py>>(
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
53 _with_gil: &T,
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
54 ) -> cpython::Python<'py> {
52555
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
55 // safety: this is safe because the returned object has the same lifetime
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52554
diff changeset
56 // as the incoming object.
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
57 unsafe { cpython::Python::assume_gil_acquired() }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
58 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
59
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
60 /// Force PyO3 GIL handle from cpython's.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
61 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
62 /// Very similar to [`cpython_handle`]
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
63 pub fn pyo3_handle(_py: cpython::Python<'_>) -> Python<'_> {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
64 // safety: this is safe because the returned object has the same lifetime
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
65 // as the incoming object.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
66 unsafe { Python::assume_gil_acquired() }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
67 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
68
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
69 /// Convert a PyO3 [`PyObject`] into a [`cpython::PyObject`]
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
70 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
71 /// During this process, the reference count is increased, then decreased.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
72 /// This means that the GIL (symbolized by the lifetime on the `obj`
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
73 /// argument) is needed.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
74 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
75 /// We could make something perhaps more handy by simply stealing the
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
76 /// pointer, forgetting the incoming and then implement `From` with "newtype".
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
77 /// It would be worth the effort for a generic cpython-to-pyo3 crate, perhaps
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
78 /// not for the current endeavour.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
79 pub(crate) fn to_cpython_py_object<'py>(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
80 obj: &Bound<'py, PyAny>,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
81 ) -> (cpython::Python<'py>, cpython::PyObject) {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
82 let py = cpython_handle(obj);
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
83 // public alias of the private cpython::fii::PyObject (!)
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
84 let raw = obj.as_ptr() as *mut python3_sys::PyObject;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
85 // both pyo3 and rust-cpython will decrement the refcount on drop.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
86 // If we use from_owned_ptr, that's a segfault.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
87 (py, unsafe { cpython::PyObject::from_borrowed_ptr(py, raw) })
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
88 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
89
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
90 /// Convert a [`cpython::PyObject`] into a PyO3 [`PyObject`]
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
91 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
92 /// During this process, the reference count is increased, then decreased.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
93 /// This means that the GIL (symbolized by the PyO3 [`Python`] handle is
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
94 /// needed.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
95 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
96 /// We could make something perhaps more handy by simply stealing the
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
97 /// pointer, forgetting the incoming and then implement `From` with "newtype".
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
98 /// It would be worth the effort for a generic cpython-to-pyo3 crate, perhaps
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
99 /// not for the current endeavour.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
100 pub(crate) fn from_cpython_py_object(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
101 py: Python<'_>,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
102 obj: cpython::PyObject,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
103 ) -> PyObject {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
104 let raw = obj.as_ptr() as *mut pyo3::ffi::PyObject;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
105 unsafe { Py::from_borrowed_ptr(py, raw) }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
106 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
107
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
108 /// Convert [`cpython::PyErr`] into [`pyo3::PyErr`]
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
109 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
110 /// The exception class remains the same as the original exception,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
111 /// hence if it is also defined in another dylib based on `cpython` crate,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
112 /// it will need to be converted to be downcasted in this crate.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
113 pub(crate) fn from_cpython_pyerr(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
114 py: cpython::Python<'_>,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
115 mut e: cpython::PyErr,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
116 ) -> PyErr {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
117 let pyo3_py = pyo3_handle(py);
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
118 let cpython_exc_obj = e.instance(py);
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
119 let pyo3_exc_obj = from_cpython_py_object(pyo3_py, cpython_exc_obj);
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
120 PyErr::from_value(pyo3_exc_obj.into_bound(pyo3_py))
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
121 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
122
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
123 /// Retrieve the PyType for objects from the `mercurial.rustext` crate.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
124 fn retrieve_cpython_py_type(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
125 submodule_name: &str,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
126 type_name: &str,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
127 ) -> cpython::PyResult<cpython::PyType> {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
128 let guard = cpython::Python::acquire_gil();
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
129 let py = guard.python();
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
130 let module = py.import(&format!("mercurial.rustext.{submodule_name}"))?;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
131 module.get(py, type_name)?.extract::<cpython::PyType>(py)
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
132 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
133
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
134 lazy_static! {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
135 static ref INNER_REVLOG_PY_TYPE: cpython::PyType = {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
136 retrieve_cpython_py_type("revlog", "InnerRevlog")
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
137 .expect("Could not import InnerRevlog in Python")
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
138 };
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
139 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
140
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
141 /// Downcast [`InnerRevlog`], with the appropriate Python type checking.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
142 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
143 /// The PyType object representing the `InnerRevlog` Python class is not the
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
144 /// the same in this dylib as it is in the `mercurial.rustext` module.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
145 /// This is because the code created with the [`cpython::py_class!`]
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
146 /// macro is itself duplicated in both dylibs. In the case of this crate, this
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
147 /// happens by linking to the [`rusthg`] crate and provides the `InnerRevlog`
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
148 /// that is visible from this crate. The `InnerRevlog::get_type` associated
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
149 /// function turns out to return a `static mut` (look for `TYPE_OBJECT` in
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
150 /// `py_class_impl3.rs`), which obviously is different in both dylibs.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
151 ///
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
152 /// The consequence of that is that downcasting an `InnerRevlog` originally
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
153 /// from the `mecurial.rustext` module to our `InnerRevlog` cannot be done with
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
154 /// the usual `extract::<InnerRevlog>(py)`, as it would perform the type
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
155 /// checking with the `PyType` that is embedded in `mercurial.pyo3_rustext`.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
156 /// We must check the `PyType` that is within `mercurial.rustext` instead.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
157 /// This is what this function does.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
158 fn extract_inner_revlog(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
159 py: cpython::Python,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
160 inner_revlog: cpython::PyObject,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
161 ) -> PyResult<InnerRevlog> {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
162 if !(*INNER_REVLOG_PY_TYPE).is_instance(py, &inner_revlog) {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
163 return Err(PyTypeError::new_err("Not an InnerRevlog instance"));
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
164 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
165 // Safety: this is safe because we checked the PyType already, with the
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
166 // value embedded in `mercurial.rustext`.
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
167 Ok(unsafe { InnerRevlog::unchecked_downcast_from(inner_revlog) })
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
168 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
169
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
170 /// This is similar to [`rusthg.py_rust_index_to_graph`], with difference in
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
171 /// how we retrieve the [`InnerRevlog`].
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
172 pub fn py_rust_index_to_graph(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
173 py: cpython::Python,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
174 index_proxy: cpython::PyObject,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
175 ) -> PyResult<cpython::UnsafePyLeaked<PySharedIndex>> {
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
176 let inner_revlog = extract_inner_revlog(
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
177 py,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
178 index_proxy
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
179 .getattr(py, "inner")
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
180 .map_err(|e| from_cpython_pyerr(py, e))?,
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
181 )?;
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
182
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
183 let leaked = inner_revlog.pub_inner(py).leak_immutable();
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
184 // Safety: we don't leak the "faked" reference out of the `UnsafePyLeaked`
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
185 Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: &idx.index }) })
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
186 }
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
187
52554
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
188 pub(crate) fn proxy_index_py_leak<'py>(
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
189 index_proxy: &Bound<'py, PyAny>,
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
190 ) -> PyResult<(cpython::Python<'py>, cpython::UnsafePyLeaked<PySharedIndex>)> {
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
191 let (py, idx_proxy) = to_cpython_py_object(index_proxy);
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
192 let py_leaked = py_rust_index_to_graph(py, idx_proxy)?;
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
193 Ok((py, py_leaked))
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
194 }
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
195
52445
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
196 /// Full extraction of the proxy index object as received in PyO3 to a
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
197 /// [`CoreIndex`] reference.
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
198 ///
52554
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
199 /// # Safety
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
200 ///
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
201 /// The invariants to maintain are those of the underlying
52445
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
202 /// [`UnsafePyLeaked::try_borrow`]: the caller must not leak the inner
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
203 /// reference.
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
204 pub(crate) unsafe fn proxy_index_extract<'py>(
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
205 index_proxy: &Bound<'py, PyAny>,
52445
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
206 ) -> PyResult<&'py CoreIndex> {
52554
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52445
diff changeset
207 let (py, py_leaked) = proxy_index_py_leak(index_proxy)?;
52445
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
208 let py_shared = &*unsafe {
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
209 py_leaked
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
210 .try_borrow(py)
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
211 .map_err(|e| from_cpython_pyerr(py, e))?
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
212 };
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52442
diff changeset
213 Ok(py_shared.inner)
52442
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
214 }
52556
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
215
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
216 /// Error propagation for an [`UnsafePyLeaked`] wrapping a [`Result`]
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
217 ///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
218 /// TODO (will consider when implementing UnsafePyLeaked in PyO3):
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
219 /// It would be nice for UnsafePyLeaked to provide this directly as a variant
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
220 /// of the `map` method with a signature such as:
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
221 ///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
222 /// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
223 /// unsafe fn map_or_err(&self,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
224 /// py: Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
225 /// f: impl FnOnce(T) -> Result(U, E),
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
226 /// convert_err: impl FnOnce(E) -> PyErr)
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
227 /// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
228 ///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
229 /// This would spare users of the `cpython` crate the additional `unsafe` deref
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
230 /// to inspect the error and return it outside `UnsafePyLeaked`, and the
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
231 /// subsequent unwrapping that this function performs.
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
232 #[allow(dead_code)]
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
233 pub(crate) fn py_leaked_or_map_err<T, E: std::fmt::Debug + Copy>(
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
234 py: cpython::Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
235 leaked: cpython::UnsafePyLeaked<Result<T, E>>,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
236 convert_err: impl FnOnce(E) -> PyErr,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
237 ) -> PyResult<cpython::UnsafePyLeaked<T>> {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
238 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
239 if let Err(e) = *unsafe {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
240 leaked
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
241 .try_borrow(py)
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
242 .map_err(|e| from_cpython_pyerr(py, e))?
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
243 } {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
244 return Err(convert_err(e));
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
245 }
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
246 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
247 Ok(unsafe {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
248 leaked.map(py, |res| {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
249 res.expect("Error case should have already be treated")
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
250 })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
251 })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52555
diff changeset
252 }