diff --git a/src/instance.rs b/src/instance.rs index d89734ebc68..907c57f86f7 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -9,6 +9,7 @@ use crate::{ PyTypeInfo, Python, ToPyObject, }; use crate::{gil, PyTypeCheck}; +use std::hash::Hasher; use std::marker::PhantomData; use std::mem::{self, ManuallyDrop}; use std::ops::Deref; @@ -217,6 +218,10 @@ impl<'py, T> Py2<'py, T> { // the reference count ManuallyDrop::new(self).1 .0 } + + pub(crate) fn detached_borrow<'a>(&'a self) -> PyBorrowedDetached<'a, T> { + self.1.detached_borrow() + } } unsafe impl AsPyPointer for Py2<'_, T> { @@ -235,6 +240,23 @@ pub(crate) struct Py2Borrowed<'a, 'py, T>( pub(crate) PhantomData<&'a Py2<'py, T>>, ); // TODO is it useful to have the generic form? +pub(crate) struct PyBorrowedDetached<'a, T>(NonNull, PhantomData<&'a Py>); + +impl<'py, T> PyBorrowedDetached<'py, T> +where + T: HasPyGilRef, +{ + pub(crate) fn from_gil_ref(gil_ref: &'py T::AsRefTarget) -> Self { + Self(unsafe { std::mem::transmute(gil_ref) }, PhantomData) + } +} + +impl PyBorrowedDetached<'_, T> { + pub(crate) fn as_ptr(&self) -> *mut ffi::PyObject { + self.0.as_ptr() + } +} + impl<'a, 'py> Py2Borrowed<'a, 'py, PyAny> { /// # Safety /// This is similar to `std::slice::from_raw_parts`, the lifetime `'a` is completely defined by @@ -697,6 +719,10 @@ impl Py { std::mem::forget(self); ptr } + + pub(crate) fn detached_borrow<'a>(&'a self) -> PyBorrowedDetached<'a, T> { + PyBorrowedDetached(self.0, PhantomData) + } } impl Py diff --git a/src/types/bytes.rs b/src/types/bytes.rs index d168b663268..7f3f5f74656 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,4 +1,4 @@ -use crate::instance::{Py2, Py2Borrowed}; +use crate::instance::{Py2, Py2Borrowed, PyBorrowedDetached}; use crate::{ffi, FromPyObject, IntoPy, Py, PyAny, PyResult, Python, ToPyObject}; use std::borrow::Cow; use std::ops::Index; @@ -89,7 +89,7 @@ impl PyBytes { /// Gets the Python string as a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { - Py2Borrowed::from_gil_ref(self).as_bytes() + PyBorrowedDetached::from_gil_ref(self).as_bytes(self.py()) } } @@ -107,13 +107,13 @@ pub(crate) trait PyBytesMethods<'py> { impl<'py> PyBytesMethods<'py> for Py2<'py, PyBytes> { #[inline] fn as_bytes(&self) -> &[u8] { - Py2Borrowed::from(self).as_bytes() + self.detached_borrow().as_bytes(self.py()) } } -impl<'a> Py2Borrowed<'a, '_, PyBytes> { +impl<'a> PyBorrowedDetached<'a, PyBytes> { /// Gets the Python string as a byte slice. - fn as_bytes(self) -> &'a [u8] { + fn as_bytes(self, _py: Python<'_>) -> &'a [u8] { unsafe { let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8; let length = ffi::PyBytes_Size(self.as_ptr()) as usize; @@ -127,8 +127,8 @@ impl Py { /// Gets the Python bytes as a byte slice. Because Python bytes are /// immutable, the result may be used for as long as the reference to /// `self` is held, including when the GIL is released. - pub fn as_bytes<'a>(&'a self, _py: Python<'_>) -> &'a [u8] { - Py2Borrowed(self.as_non_null(), std::marker::PhantomData).as_bytes() + pub fn as_bytes<'a>(&'a self, py: Python<'_>) -> &'a [u8] { + self.detached_borrow().as_bytes(py) } }