rust/hg-pyo3/src/utils.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Tue, 18 Feb 2025 11:33:20 +0100
changeset 52976 d934d730c6c2
parent 52852 6b3b69b32a41
child 52977 0c7ac026ed63
permissions -rw-r--r--
pyO3: remove useless (and wrong) `__doc__` attribute on modules PyO3 overrides the `__doc__` attributes to use the module's docstring.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     1
use hg::errors::HgError;
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
     2
use hg::revlog::index::Index as CoreIndex;
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     3
use hg::revlog::inner_revlog::RevisionBuffer;
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
     4
use pyo3::buffer::{Element, PyBuffer};
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
     5
use pyo3::exceptions::PyValueError;
52407
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
     6
use pyo3::prelude::*;
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
     7
use pyo3::types::{PyBytes, PyDict};
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
     8
use pyo3_sharedref::SharedByPyObject;
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
     9
use stable_deref_trait::StableDeref;
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
    10
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    11
use crate::revlog::{InnerRevlog, PySharedIndex};
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    12
52407
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    13
/// Create the module, with `__package__` given from parent
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    14
///
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    15
/// According to PyO3 documentation, which links to
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    16
/// <https://github.com/PyO3/pyo3/issues/1517>, the same convoluted
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    17
/// write to sys.modules has to be made as with the `cpython` crate.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    18
pub(crate) fn new_submodule<'py>(
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    19
    py: Python<'py>,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    20
    package_name: &str,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    21
    name: &str,
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    22
) -> PyResult<Bound<'py, PyModule>> {
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    23
    let dotted_name = &format!("{}.{}", package_name, name);
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    24
    let m = PyModule::new(py, name)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    25
    m.add("__package__", package_name)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    26
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    27
    let sys = PyModule::import(py, "sys")?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    28
    // according to the doc, we could make a static PyString out of
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    29
    // "modules" with the `intern!` macro, but this is used only at
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    30
    // registration so it may not be worth the effort.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    31
    let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.extract()?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    32
    sys_modules.set_item(dotted_name, &m)?;
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    33
    // Example C code (see pyexpat.c and import.c) will "give away the
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    34
    // reference", but we won't because it will be consumed once the
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    35
    // Rust PyObject is dropped.
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    36
    Ok(m)
c5128c541021 rust-pyo3: facility for submodule registration, using it for dagop
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
diff changeset
    37
}
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
    38
52836
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    39
/// Retrieve the shared index wrapper (which contains the core index)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    40
/// from the Python index proxy.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    41
pub fn py_rust_index_to_graph(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    42
    index_proxy: &Bound<'_, PyAny>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    43
) -> PyResult<SharedByPyObject<PySharedIndex>> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    44
    let py_irl = index_proxy.getattr("inner")?;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    45
    let py_irl_ref = py_irl.downcast::<InnerRevlog>()?.borrow();
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    46
    let shareable_irl = &py_irl_ref.irl;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    47
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    48
    // Safety: the owner is the actual one and we do not leak any
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    49
    // internal reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    50
    let index =
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    51
        unsafe { shareable_irl.share_map(&py_irl, |irl| (&irl.index).into()) };
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    52
    Ok(index)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    53
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    54
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    55
/// Error propagation for an [`SharedByPyObject`] wrapping a [`Result`]
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    56
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    57
/// It would be nice for [`SharedByPyObject`] to provide this directly as
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    58
/// a variant of the `map` method with a signature such as:
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    59
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    60
/// ```
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    61
///   unsafe fn map_or_err(&self,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    62
///                        py: Python,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    63
///                        f: impl FnOnce(T) -> Result(U, E),
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    64
///                        convert_err: impl FnOnce(E) -> PyErr)
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    65
/// ```
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    66
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    67
/// This would spare users of the `pyo3` crate the additional `unsafe` deref
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    68
/// to inspect the error and return it outside `SharedByPyObject`, and the
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    69
/// subsequent unwrapping that this function performs.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    70
pub(crate) fn py_shared_or_map_err<T, E: std::fmt::Debug + Copy>(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    71
    py: Python,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    72
    leaked: SharedByPyObject<Result<T, E>>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    73
    convert_err: impl FnOnce(E) -> PyErr,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    74
) -> PyResult<SharedByPyObject<T>> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    75
    // Safety: we don't leak the "faked" reference out of `SharedByPyObject`
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    76
    if let Err(e) = *unsafe { leaked.try_borrow(py)? } {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    77
        return Err(convert_err(e));
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    78
    }
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    79
    // Safety: we don't leak the "faked" reference out of `SharedByPyObject`
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    80
    Ok(unsafe {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    81
        leaked.map(py, |res| {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    82
            res.expect("Error case should have already be treated")
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    83
        })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    84
    })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    85
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    86
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    87
/// Full extraction of the proxy index object as received in PyO3 to a
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    88
/// [`CoreIndex`] reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    89
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    90
/// # Safety
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    91
///
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    92
/// The invariants to maintain are those of the underlying
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    93
/// [`SharedByPyObject::try_borrow`]: the caller must not leak the inner
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    94
/// reference.
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    95
pub(crate) unsafe fn proxy_index_extract<'py>(
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    96
    index_proxy: &Bound<'py, PyAny>,
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    97
) -> PyResult<&'py CoreIndex> {
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    98
    let py_shared = py_rust_index_to_graph(index_proxy)?;
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
    99
    let py_shared = &*unsafe { py_shared.try_borrow(index_proxy.py())? };
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   100
    Ok(unsafe { py_shared.static_inner() })
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   101
}
9749a97d3cfb rust-pyo3: introduce utils to get the pyo3-wrapped index from Python
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52830
diff changeset
   102
52780
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   103
/// Type shortcut for the kind of bytes slice trait objects that are used in
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   104
/// particular for mmap data
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   105
type BoxedBytesSlice =
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   106
    Box<dyn std::ops::Deref<Target = [u8]> + Send + Sync + 'static>;
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   107
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   108
/// Take a Python object backed by a Python buffer, and return the underlying
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   109
/// [`PyBuffer`] along with the Rust slice into said buffer.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   110
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   111
/// The caller needs to make sure that the Python buffer is not freed before
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   112
/// the slice, otherwise we'd get a dangling pointer once the incoming
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   113
/// object is freed from Python side. This can be achieved by storing it a
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   114
/// Python object.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   115
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   116
/// The typical use case is to extract mmap data to make it useable in the
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   117
/// constructs from the `hg` crate.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   118
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   119
/// # Safety
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   120
///
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   121
/// The caller must make sure that the incoming Python object is kept around
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   122
/// for at least as long as the returned [`BoxedBytesSlice`].
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   123
// TODO in PyO3, we already get a reference with two lifetimes, and we
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   124
// could even take a `Borrowed<'a, 'py, T>`.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   125
// So perhaps we could tie everything together with a lifetime so that is
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   126
// is, after all, safe, and this could be called something like `share_buffer`.
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   127
#[deny(unsafe_op_in_unsafe_fn)]
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   128
pub unsafe fn take_buffer_with_slice(
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   129
    data: &Bound<'_, PyAny>,
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   130
) -> PyResult<(PyBuffer<u8>, BoxedBytesSlice)> {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   131
    let buf = PyBuffer::<u8>::get(data)?;
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   132
    let len = buf.item_count();
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   133
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   134
    // Build a slice from the buffer data
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   135
    let cbuf = buf.buf_ptr();
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   136
    let bytes = if std::mem::size_of::<u8>() == buf.item_size()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   137
        && buf.is_c_contiguous()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   138
        && u8::is_compatible_format(buf.format())
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   139
        && buf.dimensions() == 1
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   140
        && buf.readonly()
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   141
    {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   142
        unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   143
    } else {
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   144
        return Err(PyValueError::new_err(
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   145
            "buffer has an invalid memory representation",
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   146
        ));
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   147
    };
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   148
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   149
    Ok((buf, Box::new(bytes)))
42b219a1404a rust-pyo3-revlog: InnerRevlog definition and constructor
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52407
diff changeset
   150
}
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   151
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   152
/// Takes an initialization function `init` which writes bytes to a
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   153
/// Python-backed buffer, to save on a (potentially large) memory allocation
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   154
/// and copy. If `init` fails to write the full expected length `len`, an error
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   155
/// is raised.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   156
pub fn with_pybytes_buffer<F>(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   157
    py: Python,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   158
    len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   159
    init: F,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   160
) -> Result<Py<PyBytes>, hg::revlog::RevlogError>
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   161
where
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   162
    F: FnOnce(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   163
        &mut dyn RevisionBuffer<Target = Py<PyBytes>>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   164
    ) -> Result<(), hg::revlog::RevlogError>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   165
{
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   166
    // Largely inspired by code in PyO3
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   167
    // https://pyo3.rs/main/doc/pyo3/types/struct.pybytes#method.new_bound_with
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   168
    unsafe {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   169
        let pyptr = pyo3::ffi::PyBytes_FromStringAndSize(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   170
            std::ptr::null(),
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   171
            len as pyo3::ffi::Py_ssize_t,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   172
        );
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   173
        let pybytes = Bound::from_owned_ptr_or_err(py, pyptr)
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   174
            .map_err(|e| HgError::abort_simple(e.to_string()))?
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   175
            .downcast_into_unchecked();
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   176
        let buffer: *mut u8 = pyo3::ffi::PyBytes_AsString(pyptr).cast();
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   177
        debug_assert!(!buffer.is_null());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   178
        let mut rev_buf = PyRevisionBuffer::new(pybytes.unbind(), buffer, len);
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   179
        // Initialise the bytestring in init
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   180
        // If init returns an Err, the buffer is deallocated by `pybytes`
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   181
        init(&mut rev_buf).map(|_| rev_buf.finish())
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   182
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   183
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   184
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   185
/// Safe abstraction over a `PyBytes` together with the `&[u8]` slice
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   186
/// that borrows it. Implements `Deref<Target = [u8]>`.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   187
///
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   188
/// Calling `PyBytes::data` requires a GIL marker but we want to access the
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   189
/// data in a thread that (ideally) does not need to acquire the GIL.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   190
/// This type allows separating the call an the use.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   191
///
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   192
/// It also enables using a (wrapped) `PyBytes` in GIL-unaware generic code.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   193
pub struct PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   194
    #[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   195
    keep_alive: Py<PyBytes>,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   196
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   197
    /// Borrows the buffer inside `self.keep_alive`,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   198
    /// but the borrow-checker cannot express self-referential structs.
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   199
    data: &'static [u8],
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   200
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   201
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   202
impl PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   203
    pub fn new(py: Python, bytes: Py<PyBytes>) -> Self {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   204
        let as_raw: *const [u8] = bytes.as_bytes(py);
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   205
        Self {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   206
            // Safety: the raw pointer is valid as long as the PyBytes is still
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   207
            // alive, and the objecs owns it.
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   208
            data: unsafe { &*as_raw },
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   209
            keep_alive: bytes,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   210
        }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   211
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   212
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   213
    #[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   214
    pub fn unwrap(self) -> Py<PyBytes> {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   215
        self.keep_alive
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   216
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   217
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   218
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   219
impl std::ops::Deref for PyBytesDeref {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   220
    type Target = [u8];
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   221
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   222
    fn deref(&self) -> &[u8] {
52852
6b3b69b32a41 rust-pyo3: making PyBytesDeref Sync
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52841
diff changeset
   223
        self.data
52830
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   224
    }
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   225
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   226
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   227
unsafe impl StableDeref for PyBytesDeref {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   228
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   229
fn require_send<T: Send>() {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   230
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   231
#[allow(unused)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   232
fn static_assert_pybytes_is_send() {
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   233
    #[allow(clippy::no_effect)]
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   234
    require_send::<Py<PyBytes>>;
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   235
}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   236
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   237
// Safety: `[Py<PyBytes>]` is Send. Raw pointers are not by default,
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   238
// but here sending one to another thread is fine since we ensure it stays
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   239
// valid.
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   240
unsafe impl Send for PyBytesDeref {}
dd3a2948804f rust-pyo3: add `PyBytesDeref` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52822
diff changeset
   241
52822
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   242
/// Wrapper around a Python-provided buffer into which the revision contents
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   243
/// will be written. Done for speed in order to save a large allocation + copy.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   244
struct PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   245
    py_bytes: Py<PyBytes>,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   246
    _buf: *mut u8,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   247
    len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   248
    current_buf: *mut u8,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   249
    current_len: usize,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   250
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   251
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   252
impl PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   253
    /// # Safety
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   254
    ///
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   255
    /// `buf` should be the start of the allocated bytes of `bytes`, and `len`
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   256
    /// exactly the length of said allocated bytes.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   257
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   258
    unsafe fn new(bytes: Py<PyBytes>, buf: *mut u8, len: usize) -> Self {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   259
        Self {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   260
            py_bytes: bytes,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   261
            _buf: buf,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   262
            len,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   263
            current_len: 0,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   264
            current_buf: buf,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   265
        }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   266
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   267
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   268
    /// Number of bytes that have been copied to. Will be different to the
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   269
    /// total allocated length of the buffer unless the revision is done being
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   270
    /// written.
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   271
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   272
    fn current_len(&self) -> usize {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   273
        self.current_len
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   274
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   275
}
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   276
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   277
impl RevisionBuffer for PyRevisionBuffer {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   278
    type Target = Py<PyBytes>;
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   279
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   280
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   281
    fn extend_from_slice(&mut self, slice: &[u8]) {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   282
        assert!(self.current_len + slice.len() <= self.len);
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   283
        unsafe {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   284
            // We cannot use `copy_from_nonoverlapping` since it's *possible*
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   285
            // to create a slice from the same Python memory region using
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   286
            // [`PyBytesDeref`]. Probable that LLVM has an optimization anyway?
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   287
            self.current_buf.copy_from(slice.as_ptr(), slice.len());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   288
            self.current_buf = self.current_buf.add(slice.len());
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   289
        }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   290
        self.current_len += slice.len()
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   291
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   292
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   293
    #[inline]
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   294
    fn finish(self) -> Self::Target {
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   295
        // catch unzeroed bytes before it becomes undefined behavior
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   296
        assert_eq!(
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   297
            self.current_len(),
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   298
            self.len,
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   299
            "not enough bytes read for revision"
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   300
        );
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   301
        self.py_bytes
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   302
    }
4f41a8acf350 rust-pyo3: add a `with_pybytes_buffer` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52780
diff changeset
   303
}