rust/hg-pyo3/src/convert_cpython.rs
author Pierre-Yves David <pierre-yves.david@octobus.net>
Thu, 02 Jan 2025 14:50:06 +0100
changeset 52592 87ceb51d124c
parent 52533 6b694bdf752a
permissions -rw-r--r--
run-tests: drop jython support I don't think we heard anything about jython support for the past 15 years, so let's drop special support for it in run-tests.py it is most probably broken at that point.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52411
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::*;
52528
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
diff changeset
    14
use pyo3::{pyclass::boolean_struct::False, PyClass};
52411
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
52414
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
    20
use hg::revlog::index::Index as CoreIndex;
52411
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
52528
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
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: 52527
diff changeset
    24
///
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
diff changeset
    25
/// # Safety
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
diff changeset
    26
///
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
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: 52527
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: 52527
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: 52527
diff changeset
    30
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
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: 52527
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: 52527
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: 52527
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: 52527
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: 52527
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: 52527
diff changeset
    37
{
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
diff changeset
    38
}
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
diff changeset
    39
52411
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>
52528
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
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: 52527
diff changeset
    53
    _with_gil: &T,
52411
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    54
) -> cpython::Python<'py> {
52528
1dd673c1ab3b rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52527
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: 52527
diff changeset
    56
    // as the incoming object.
52411
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
52527
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   188
pub(crate) fn proxy_index_py_leak<'py>(
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   189
    index_proxy: &Bound<'py, PyAny>,
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   190
) -> PyResult<(cpython::Python<'py>, cpython::UnsafePyLeaked<PySharedIndex>)> {
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
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: 52414
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: 52414
diff changeset
   193
    Ok((py, py_leaked))
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   194
}
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   195
52414
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
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: 52411
diff changeset
   197
/// [`CoreIndex`] reference.
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   198
///
52527
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   199
/// # Safety
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   200
///
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   201
/// The invariants to maintain are those of the underlying
52414
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
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: 52411
diff changeset
   203
/// reference.
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   204
pub(crate) unsafe fn proxy_index_extract<'py>(
52411
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
   205
    index_proxy: &Bound<'py, PyAny>,
52414
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   206
) -> PyResult<&'py CoreIndex> {
52527
64a618048ba8 rust-pyo3: intermediate ProxyIndex extraction
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52414
diff changeset
   207
    let (py, py_leaked) = proxy_index_py_leak(index_proxy)?;
52414
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   208
    let py_shared = &*unsafe {
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   209
        py_leaked
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   210
            .try_borrow(py)
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
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: 52411
diff changeset
   212
    };
233707101dae rust-pyo3: simplified API to get core Index references
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52411
diff changeset
   213
    Ok(py_shared.inner)
52411
c2480ac4c5e2 rust-pyo3: retrieving the InnerRevlog of hg-cpython
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
   214
}
52529
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   215
52530
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   216
/// Generic borrow of [`cpython::UnsafePyLeaked`], with proper mapping.
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   217
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   218
/// # Safety
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   219
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   220
/// The invariants to maintain are those of the underlying
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   221
/// [`UnsafePyLeaked::try_borrow`]: the caller must not leak the inner
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   222
/// static reference. It is possible, depending on `T` that such a leak cannot
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   223
/// occur in practice. We may later on define a marker trait for this,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   224
/// which will allow us to make declare this function to be safe.
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   225
pub(crate) unsafe fn py_leaked_borrow<'a, 'py: 'a, T>(
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   226
    py: &impl WithGIL<'py>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   227
    leaked: &'a cpython::UnsafePyLeaked<T>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   228
) -> PyResult<cpython::PyLeakedRef<'a, T>> {
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   229
    let py = cpython_handle(py);
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   230
    leaked.try_borrow(py).map_err(|e| from_cpython_pyerr(py, e))
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   231
}
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   232
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   233
/// Mutable variant of [`py_leaked_borrow`]
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   234
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   235
/// # Safety
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   236
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   237
/// See [`py_leaked_borrow`]
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   238
pub(crate) unsafe fn py_leaked_borrow_mut<'a, 'py: 'a, T>(
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   239
    py: &impl WithGIL<'py>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   240
    leaked: &'a mut cpython::UnsafePyLeaked<T>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   241
) -> PyResult<cpython::PyLeakedRefMut<'a, T>> {
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   242
    let py = cpython_handle(py);
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   243
    leaked
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   244
        .try_borrow_mut(py)
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   245
        .map_err(|e| from_cpython_pyerr(py, e))
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   246
}
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   247
52529
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   248
/// 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: 52528
diff changeset
   249
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   250
/// 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: 52528
diff changeset
   251
/// 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: 52528
diff changeset
   252
/// 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: 52528
diff changeset
   253
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   254
/// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   255
///   unsafe fn map_or_err(&self,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   256
///                        py: Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   257
///                        f: impl FnOnce(T) -> Result(U, E),
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   258
///                        convert_err: impl FnOnce(E) -> PyErr)
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   259
/// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   260
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   261
/// 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: 52528
diff changeset
   262
/// 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: 52528
diff changeset
   263
/// subsequent unwrapping that this function performs.
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   264
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: 52528
diff changeset
   265
    py: cpython::Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   266
    leaked: cpython::UnsafePyLeaked<Result<T, E>>,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   267
    convert_err: impl FnOnce(E) -> PyErr,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   268
) -> PyResult<cpython::UnsafePyLeaked<T>> {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   269
    // 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: 52528
diff changeset
   270
    if let Err(e) = *unsafe {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   271
        leaked
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   272
            .try_borrow(py)
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   273
            .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: 52528
diff changeset
   274
    } {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   275
        return Err(convert_err(e));
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   276
    }
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   277
    // 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: 52528
diff changeset
   278
    Ok(unsafe {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   279
        leaked.map(py, |res| {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   280
            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: 52528
diff changeset
   281
        })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   282
    })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   283
}