allow borrowed extracts with `gil-refs` disabled (#3959)
This commit is contained in:
parent
989d2c53ab
commit
5c86dc35c1
|
@ -6,7 +6,9 @@ use crate::pyclass::boolean_struct::False;
|
||||||
use crate::type_object::PyTypeInfo;
|
use crate::type_object::PyTypeInfo;
|
||||||
use crate::types::any::PyAnyMethods;
|
use crate::types::any::PyAnyMethods;
|
||||||
use crate::types::PyTuple;
|
use crate::types::PyTuple;
|
||||||
use crate::{ffi, gil, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python};
|
use crate::{
|
||||||
|
ffi, gil, Borrowed, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
|
||||||
|
};
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
/// Returns a borrowed pointer to a Python object.
|
/// Returns a borrowed pointer to a Python object.
|
||||||
|
@ -288,7 +290,7 @@ pub trait FromPyObjectBound<'a, 'py>: Sized + from_py_object_bound_sealed::Seale
|
||||||
///
|
///
|
||||||
/// Users are advised against calling this method directly: instead, use this via
|
/// Users are advised against calling this method directly: instead, use this via
|
||||||
/// [`Bound<'_, PyAny>::extract`] or [`Py::extract`].
|
/// [`Bound<'_, PyAny>::extract`] or [`Py::extract`].
|
||||||
fn from_py_object_bound(ob: &'a Bound<'py, PyAny>) -> PyResult<Self>;
|
fn from_py_object_bound(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self>;
|
||||||
|
|
||||||
/// Extracts the type hint information for this type when it appears as an argument.
|
/// Extracts the type hint information for this type when it appears as an argument.
|
||||||
///
|
///
|
||||||
|
@ -307,8 +309,8 @@ impl<'py, T> FromPyObjectBound<'_, 'py> for T
|
||||||
where
|
where
|
||||||
T: FromPyObject<'py>,
|
T: FromPyObject<'py>,
|
||||||
{
|
{
|
||||||
fn from_py_object_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
|
fn from_py_object_bound(ob: Borrowed<'_, 'py, PyAny>) -> PyResult<Self> {
|
||||||
Self::extract_bound(ob)
|
Self::extract_bound(&ob)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "experimental-inspect")]
|
#[cfg(feature = "experimental-inspect")]
|
||||||
|
|
|
@ -2,11 +2,9 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
#[cfg(feature = "experimental-inspect")]
|
#[cfg(feature = "experimental-inspect")]
|
||||||
use crate::inspect::types::TypeInfo;
|
use crate::inspect::types::TypeInfo;
|
||||||
#[cfg(not(feature = "gil-refs"))]
|
|
||||||
use crate::types::PyBytesMethods;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
types::{PyAnyMethods, PyByteArray, PyByteArrayMethods, PyBytes},
|
types::{PyByteArray, PyByteArrayMethods, PyBytes},
|
||||||
Bound, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
|
IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> IntoPy<PyObject> for &'a [u8] {
|
impl<'a> IntoPy<PyObject> for &'a [u8] {
|
||||||
|
@ -34,7 +32,7 @@ impl<'py> crate::FromPyObject<'py> for &'py [u8] {
|
||||||
|
|
||||||
#[cfg(not(feature = "gil-refs"))]
|
#[cfg(not(feature = "gil-refs"))]
|
||||||
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a [u8] {
|
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a [u8] {
|
||||||
fn from_py_object_bound(obj: &'a Bound<'_, PyAny>) -> PyResult<Self> {
|
fn from_py_object_bound(obj: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
|
||||||
Ok(obj.downcast::<PyBytes>()?.as_bytes())
|
Ok(obj.downcast::<PyBytes>()?.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +49,8 @@ impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a [u8] {
|
||||||
/// If it is a `bytearray`, its contents will be copied to an owned `Cow`.
|
/// If it is a `bytearray`, its contents will be copied to an owned `Cow`.
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
impl<'py> crate::FromPyObject<'py> for Cow<'py, [u8]> {
|
impl<'py> crate::FromPyObject<'py> for Cow<'py, [u8]> {
|
||||||
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
|
fn extract_bound(ob: &crate::Bound<'py, PyAny>) -> PyResult<Self> {
|
||||||
|
use crate::types::PyAnyMethods;
|
||||||
if let Ok(bytes) = ob.downcast::<PyBytes>() {
|
if let Ok(bytes) = ob.downcast::<PyBytes>() {
|
||||||
return Ok(Cow::Borrowed(bytes.clone().into_gil_ref().as_bytes()));
|
return Ok(Cow::Borrowed(bytes.clone().into_gil_ref().as_bytes()));
|
||||||
}
|
}
|
||||||
|
@ -63,7 +62,7 @@ impl<'py> crate::FromPyObject<'py> for Cow<'py, [u8]> {
|
||||||
|
|
||||||
#[cfg(not(feature = "gil-refs"))]
|
#[cfg(not(feature = "gil-refs"))]
|
||||||
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, [u8]> {
|
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, [u8]> {
|
||||||
fn from_py_object_bound(ob: &'a Bound<'_, PyAny>) -> PyResult<Self> {
|
fn from_py_object_bound(ob: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
|
||||||
if let Ok(bytes) = ob.downcast::<PyBytes>() {
|
if let Ok(bytes) = ob.downcast::<PyBytes>() {
|
||||||
return Ok(Cow::Borrowed(bytes.as_bytes()));
|
return Ok(Cow::Borrowed(bytes.as_bytes()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ impl<'py> FromPyObject<'py> for &'py str {
|
||||||
|
|
||||||
#[cfg(all(not(feature = "gil-refs"), any(Py_3_10, not(Py_LIMITED_API))))]
|
#[cfg(all(not(feature = "gil-refs"), any(Py_3_10, not(Py_LIMITED_API))))]
|
||||||
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a str {
|
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a str {
|
||||||
fn from_py_object_bound(ob: &'a Bound<'_, PyAny>) -> PyResult<Self> {
|
fn from_py_object_bound(ob: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
|
||||||
ob.downcast::<PyString>()?.to_str()
|
ob.downcast::<PyString>()?.to_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl<'py> FromPyObject<'py> for Cow<'py, str> {
|
||||||
|
|
||||||
#[cfg(not(feature = "gil-refs"))]
|
#[cfg(not(feature = "gil-refs"))]
|
||||||
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, str> {
|
impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, str> {
|
||||||
fn from_py_object_bound(ob: &'a Bound<'_, PyAny>) -> PyResult<Self> {
|
fn from_py_object_bound(ob: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
|
||||||
ob.downcast::<PyString>()?.to_cow()
|
ob.downcast::<PyString>()?.to_cow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
exceptions::{self, PyBaseException},
|
exceptions::{self, PyBaseException},
|
||||||
ffi,
|
ffi,
|
||||||
};
|
};
|
||||||
use crate::{IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
|
use crate::{Borrowed, IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -65,17 +65,16 @@ impl<'a> PyDowncastError<'a> {
|
||||||
/// Compatibility API to convert the Bound variant `DowncastError` into the
|
/// Compatibility API to convert the Bound variant `DowncastError` into the
|
||||||
/// gil-ref variant
|
/// gil-ref variant
|
||||||
pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self {
|
pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self {
|
||||||
Self {
|
#[allow(deprecated)]
|
||||||
from: from.as_gil_ref(),
|
let from = unsafe { from.py().from_borrowed_ptr(from.as_ptr()) };
|
||||||
to,
|
Self { from, to }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that indicates a failure to convert a PyAny to a more specific Python type.
|
/// Error that indicates a failure to convert a PyAny to a more specific Python type.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DowncastError<'a, 'py> {
|
pub struct DowncastError<'a, 'py> {
|
||||||
from: &'a Bound<'py, PyAny>,
|
from: Borrowed<'a, 'py, PyAny>,
|
||||||
to: Cow<'static, str>,
|
to: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +82,16 @@ impl<'a, 'py> DowncastError<'a, 'py> {
|
||||||
/// Create a new `PyDowncastError` representing a failure to convert the object
|
/// Create a new `PyDowncastError` representing a failure to convert the object
|
||||||
/// `from` into the type named in `to`.
|
/// `from` into the type named in `to`.
|
||||||
pub fn new(from: &'a Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
|
pub fn new(from: &'a Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
|
||||||
|
DowncastError {
|
||||||
|
from: from.as_borrowed(),
|
||||||
|
to: to.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gil-refs"))]
|
||||||
|
pub(crate) fn new_from_borrowed(
|
||||||
|
from: Borrowed<'a, 'py, PyAny>,
|
||||||
|
to: impl Into<Cow<'static, str>>,
|
||||||
|
) -> Self {
|
||||||
DowncastError {
|
DowncastError {
|
||||||
from,
|
from,
|
||||||
to: to.into(),
|
to: to.into(),
|
||||||
|
@ -1036,7 +1045,7 @@ impl std::error::Error for DowncastError<'_, '_> {}
|
||||||
|
|
||||||
impl std::fmt::Display for DowncastError<'_, '_> {
|
impl std::fmt::Display for DowncastError<'_, '_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
display_downcast_error(f, self.from, &self.to)
|
display_downcast_error(f, &self.from, &self.to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -579,6 +579,20 @@ impl<'a, 'py> Borrowed<'a, 'py, PyAny> {
|
||||||
Self(NonNull::new_unchecked(ptr), PhantomData, py)
|
Self(NonNull::new_unchecked(ptr), PhantomData, py)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(feature = "gil-refs"))]
|
||||||
|
pub(crate) fn downcast<T>(self) -> Result<Borrowed<'a, 'py, T>, DowncastError<'a, 'py>>
|
||||||
|
where
|
||||||
|
T: PyTypeCheck,
|
||||||
|
{
|
||||||
|
if T::type_check(&self) {
|
||||||
|
// Safety: type_check is responsible for ensuring that the type is correct
|
||||||
|
Ok(unsafe { self.downcast_unchecked() })
|
||||||
|
} else {
|
||||||
|
Err(DowncastError::new_from_borrowed(self, T::NAME))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts this `PyAny` to a concrete Python type without checking validity.
|
/// Converts this `PyAny` to a concrete Python type without checking validity.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::class::basic::CompareOp;
|
use crate::class::basic::CompareOp;
|
||||||
use crate::conversion::{AsPyPointer, FromPyObject, FromPyObjectBound, IntoPy, ToPyObject};
|
use crate::conversion::{AsPyPointer, FromPyObjectBound, IntoPy, ToPyObject};
|
||||||
use crate::err::{DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyResult};
|
use crate::err::{DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyResult};
|
||||||
use crate::exceptions::{PyAttributeError, PyTypeError};
|
use crate::exceptions::{PyAttributeError, PyTypeError};
|
||||||
use crate::ffi_ptr_ext::FfiPtrExt;
|
use crate::ffi_ptr_ext::FfiPtrExt;
|
||||||
|
@ -799,13 +799,14 @@ impl PyAny {
|
||||||
|
|
||||||
/// Extracts some type from the Python object.
|
/// Extracts some type from the Python object.
|
||||||
///
|
///
|
||||||
/// This is a wrapper function around [`FromPyObject::extract()`].
|
/// This is a wrapper function around
|
||||||
|
/// [`FromPyObject::extract()`](crate::FromPyObject::extract).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extract<'py, D>(&'py self) -> PyResult<D>
|
pub fn extract<'py, D>(&'py self) -> PyResult<D>
|
||||||
where
|
where
|
||||||
D: FromPyObject<'py>,
|
D: FromPyObjectBound<'py, 'py>,
|
||||||
{
|
{
|
||||||
FromPyObject::extract(self)
|
FromPyObjectBound::from_py_object_bound(self.as_borrowed())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the reference count for the Python object.
|
/// Returns the reference count for the Python object.
|
||||||
|
@ -1641,7 +1642,8 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
|
||||||
|
|
||||||
/// Extracts some type from the Python object.
|
/// Extracts some type from the Python object.
|
||||||
///
|
///
|
||||||
/// This is a wrapper function around [`FromPyObject::extract()`].
|
/// This is a wrapper function around
|
||||||
|
/// [`FromPyObject::extract()`](crate::FromPyObject::extract).
|
||||||
fn extract<'a, T>(&'a self) -> PyResult<T>
|
fn extract<'a, T>(&'a self) -> PyResult<T>
|
||||||
where
|
where
|
||||||
T: FromPyObjectBound<'a, 'py>;
|
T: FromPyObjectBound<'a, 'py>;
|
||||||
|
@ -2182,7 +2184,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
|
||||||
where
|
where
|
||||||
T: FromPyObjectBound<'a, 'py>,
|
T: FromPyObjectBound<'a, 'py>,
|
||||||
{
|
{
|
||||||
FromPyObjectBound::from_py_object_bound(self)
|
FromPyObjectBound::from_py_object_bound(self.as_borrowed())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_refcnt(&self) -> isize {
|
fn get_refcnt(&self) -> isize {
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl<'py> PyBytesMethods<'py> for Bound<'py, PyBytes> {
|
||||||
impl<'a> Borrowed<'a, '_, PyBytes> {
|
impl<'a> Borrowed<'a, '_, PyBytes> {
|
||||||
/// Gets the Python string as a byte slice.
|
/// Gets the Python string as a byte slice.
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn as_bytes(self) -> &'a [u8] {
|
pub(crate) fn as_bytes(self) -> &'a [u8] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
|
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
|
||||||
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
|
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
|
||||||
|
|
|
@ -369,7 +369,7 @@ impl<'a> Borrowed<'a, '_, PyString> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn to_cow(self) -> PyResult<Cow<'a, str>> {
|
pub(crate) fn to_cow(self) -> PyResult<Cow<'a, str>> {
|
||||||
// TODO: this method can probably be deprecated once Python 3.9 support is dropped,
|
// TODO: this method can probably be deprecated once Python 3.9 support is dropped,
|
||||||
// because all versions then support the more efficient `to_str`.
|
// because all versions then support the more efficient `to_str`.
|
||||||
#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
|
#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
|
||||||
|
|
Loading…
Reference in New Issue