Mercurial > public > mercurial-scm > hg-stable
annotate rust/hg-pyo3/src/convert_cpython.rs @ 52442:c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
This allows PyO3-based code to use the InnerRevlog, access its shared data
(core InnerRevlog), which will then allow, e.g., to retrieve references on
the core Index.
On the `hg-cpython` (`rusthg` crate, `rustext` Python extension module),
we had to also build as a Rust library, and open up some accesses (see
notably the public accessor for `inner`, the core `InnerRevlog`).
Retrieving the Rust struct underlying a Python object defined by another
extension module written in Rust is tricky because the Python type objects
are duplicated in the extension modules, leading to failure of the normal
type checking. See the doc-comment of `convert_cpython::extract_inner_revlog`
for a complete explanation.
To solve this, we import the Python type object of `rustext` (defined
by `hg-cpython`) and perform a manual check. Checking the Python type is
necessary, as PyO3 documentation clearly state that downcasting an object
that has not the proper type is Undefined Behaviour.
At this point, we do not have conversion facilities for exceptions (`PyErr`
on both sides), hence the remaining unwraps).
author | Georges Racinet <georges.racinet@cloudcrane.io> |
---|---|
date | Sat, 30 Nov 2024 20:57:02 +0100 |
parents | |
children | 233707101dae |
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::*; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
14 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
15 use cpython::ObjectProtocol; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
16 use cpython::PythonObject; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
17 use lazy_static::lazy_static; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
18 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
19 use rusthg::revlog::{InnerRevlog, PySharedIndex}; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
20 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
21 /// 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
|
22 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
23 /// 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
|
24 /// 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
|
25 /// 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
|
26 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
27 /// 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
|
28 /// 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
|
29 /// (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
|
30 /// 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
|
31 /// reference: |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
32 /// <https://docs.python.org/3.8/c-api/init.html#c.PyGILState_Ensure> |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
33 pub(crate) fn cpython_handle<'py, T>( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
34 _bound: &Bound<'py, T>, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
35 ) -> cpython::Python<'py> { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
36 // safety: this is safe because the returned object has the 'py lifetime |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
37 unsafe { cpython::Python::assume_gil_acquired() } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
38 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
39 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
40 /// 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
|
41 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
42 /// Very similar to [`cpython_handle`] |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
43 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
|
44 // 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
|
45 // as the incoming object. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
46 unsafe { Python::assume_gil_acquired() } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
47 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
48 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
49 /// 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
|
50 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
51 /// 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
|
52 /// 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
|
53 /// argument) is needed. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
54 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
55 /// 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
|
56 /// 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
|
57 /// 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
|
58 /// not for the current endeavour. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
59 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
|
60 obj: &Bound<'py, PyAny>, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
61 ) -> (cpython::Python<'py>, cpython::PyObject) { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
62 let py = cpython_handle(obj); |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
63 // 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
|
64 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
|
65 // 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
|
66 // 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
|
67 (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
|
68 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
69 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
70 /// 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
|
71 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
72 /// 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
|
73 /// 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
|
74 /// needed. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
75 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
76 /// 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
|
77 /// 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
|
78 /// 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
|
79 /// not for the current endeavour. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
80 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
|
81 py: Python<'_>, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
82 obj: cpython::PyObject, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
83 ) -> 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 pyo3::ffi::PyObject; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
85 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
|
86 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
87 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
88 /// Convert [`cpython::PyErr`] into [`pyo3::PyErr`] |
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 /// 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
|
91 /// 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
|
92 /// 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
|
93 pub(crate) fn from_cpython_pyerr( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
94 py: cpython::Python<'_>, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
95 mut e: cpython::PyErr, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
96 ) -> PyErr { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
97 let pyo3_py = pyo3_handle(py); |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
98 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
|
99 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
|
100 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
|
101 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
102 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
103 /// 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
|
104 fn retrieve_cpython_py_type( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
105 submodule_name: &str, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
106 type_name: &str, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
107 ) -> cpython::PyResult<cpython::PyType> { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
108 let guard = cpython::Python::acquire_gil(); |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
109 let py = guard.python(); |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
110 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
|
111 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
|
112 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
113 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
114 lazy_static! { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
115 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
|
116 retrieve_cpython_py_type("revlog", "InnerRevlog") |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
117 .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
|
118 }; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
119 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
120 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
121 /// 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
|
122 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
123 /// 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
|
124 /// 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
|
125 /// 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
|
126 /// 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
|
127 /// 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
|
128 /// 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
|
129 /// 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
|
130 /// `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
|
131 /// |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
132 /// 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
|
133 /// 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
|
134 /// 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
|
135 /// 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
|
136 /// 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
|
137 /// This is what this function does. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
138 fn extract_inner_revlog( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
139 py: cpython::Python, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
140 inner_revlog: cpython::PyObject, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
141 ) -> PyResult<InnerRevlog> { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
142 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
|
143 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
|
144 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
145 // 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
|
146 // value embedded in `mercurial.rustext`. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
147 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
|
148 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
149 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
150 /// 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
|
151 /// how we retrieve the [`InnerRevlog`]. |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
152 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
|
153 py: cpython::Python, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
154 index_proxy: cpython::PyObject, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
155 ) -> PyResult<cpython::UnsafePyLeaked<PySharedIndex>> { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
156 let inner_revlog = extract_inner_revlog( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
157 py, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
158 index_proxy |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
159 .getattr(py, "inner") |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
160 .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
|
161 )?; |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
162 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
163 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
|
164 // 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
|
165 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
|
166 } |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
167 |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
168 pub(crate) fn proxy_index_extract<'py>( |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
169 index_proxy: &Bound<'py, PyAny>, |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
170 ) -> PyResult<(cpython::Python<'py>, cpython::UnsafePyLeaked<PySharedIndex>)> { |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
171 let (py, idx_proxy) = to_cpython_py_object(index_proxy); |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
172 Ok((py, py_rust_index_to_graph(py, idx_proxy)?)) |
c2480ac4c5e2
rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff
changeset
|
173 } |