rust/hg-pyo3/src/convert_cpython.rs
author Georges Racinet <georges.racinet@cloudcrane.io>
Sat, 07 Dec 2024 18:38:37 +0100
changeset 52531 4c9e31984b3a
parent 52530 736551565871
child 52532 3ffcdbf0b432
permissions -rw-r--r--
rust-pyo3: exposition of AncestorsIterator Compared to the early experiments, we have one less `RwLock` in the wrapping. Still that is somewhat redundant with `UnsafePyLeaked` being itself some kind of lock. In the original rust-cpython code, we were borrowing the `RefCell` with a method that can panic. Instead we are now converting the `PoisonError` that unlocking a `RwLock` can produce. Since all methods acquiring the `RwLock` are themselves protected by the GIL and do not release it before returning, nor do they leak RwLock guards, there is no risk of contention on these locks themselves.
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
#[allow(dead_code)]
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   226
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
   227
    py: &impl WithGIL<'py>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   228
    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
   229
) -> 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
   230
    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
   231
    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
   232
}
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   233
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   234
/// 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
   235
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   236
/// # Safety
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   237
///
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   238
/// See [`py_leaked_borrow`]
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   239
#[allow(dead_code)]
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   240
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
   241
    py: &impl WithGIL<'py>,
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   242
    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
   243
) -> 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
   244
    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
   245
    leaked
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   246
        .try_borrow_mut(py)
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   247
        .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
   248
}
736551565871 rust-pyo3: generic borrows of UnsafePyLeaked with error treatment
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52529
diff changeset
   249
52529
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   250
/// 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
   251
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   252
/// 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
   253
/// 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
   254
/// 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
   255
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   256
/// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   257
///   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
   258
///                        py: Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   259
///                        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
   260
///                        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
   261
/// ```
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   262
///
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   263
/// 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
   264
/// 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
   265
/// 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
   266
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
   267
    py: cpython::Python,
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   268
    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
   269
    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
   270
) -> PyResult<cpython::UnsafePyLeaked<T>> {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   271
    // 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
   272
    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
   273
        leaked
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   274
            .try_borrow(py)
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   275
            .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
   276
    } {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   277
        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
   278
    }
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   279
    // 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
   280
    Ok(unsafe {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   281
        leaked.map(py, |res| {
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   282
            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
   283
        })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   284
    })
bd65cb043aa5 rust-pyo3: error propagation for UnsafePyLeaked wrapping a result
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52528
diff changeset
   285
}