Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-cpython/src/pybytes_deref.rs @ 47981:8f031a274cd6
rust: Move PyBytesWithData out of copy-tracing code
So we can use it in other places to.
Replace its `.data()` method with the `Deref<Target = [u8]>` trait,
allowing this type to be used in generic contexts.
Rename the type accordingly.
Differential Revision: https://phab.mercurial-scm.org/D11395
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 06 Sep 2021 13:39:54 +0200 |
parents | |
children | 4afd6cc447b9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/src/pybytes_deref.rs Mon Sep 06 13:39:54 2021 +0200 @@ -0,0 +1,53 @@ +use cpython::{PyBytes, Python}; + +/// Safe abstraction over a `PyBytes` together with the `&[u8]` slice +/// that borrows it. Implements `Deref<Target = [u8]>`. +/// +/// Calling `PyBytes::data` requires a GIL marker but we want to access the +/// data in a thread that (ideally) does not need to acquire the GIL. +/// This type allows separating the call an the use. +/// +/// It also enables using a (wrapped) `PyBytes` in GIL-unaware generic code. +pub struct PyBytesDeref { + #[allow(unused)] + keep_alive: PyBytes, + + /// Borrows the buffer inside `self.keep_alive`, + /// but the borrow-checker cannot express self-referential structs. + data: *const [u8], +} + +impl PyBytesDeref { + pub fn new(py: Python, bytes: PyBytes) -> Self { + Self { + data: bytes.data(py), + keep_alive: bytes, + } + } + + pub fn unwrap(self) -> PyBytes { + self.keep_alive + } +} + +impl std::ops::Deref for PyBytesDeref { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + // Safety: the raw pointer is valid as long as the PyBytes is still + // alive, and the returned slice borrows `self`. + unsafe { &*self.data } + } +} + +fn require_send<T: Send>() {} + +#[allow(unused)] +fn static_assert_pybytes_is_send() { + require_send::<PyBytes>; +} + +// Safety: PyBytes is Send. Raw pointers are not by default, +// but here sending one to another thread is fine since we ensure it stays +// valid. +unsafe impl Send for PyBytesDeref {}