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
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::*;
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 }