Add {Py,PyAny}::downcast_unchecked to replace try_from_unchecked calls
This commit is contained in:
parent
d6ac4d51b7
commit
249c0209fd
|
@ -1 +1,2 @@
|
|||
Added `Py::downcast()` as a companion to `PyAny::downcast()`.
|
||||
Added `Py::downcast()` as a companion to `PyAny::downcast()`, as well as
|
||||
`downcast_unchecked()` for both types.
|
||||
|
|
|
@ -50,9 +50,7 @@ use crate::types::{
|
|||
timezone_utc, PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyTime, PyTimeAccess,
|
||||
PyTzInfo, PyTzInfoAccess, PyUnicode,
|
||||
};
|
||||
use crate::{
|
||||
AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject,
|
||||
};
|
||||
use crate::{AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
|
||||
use chrono::offset::{FixedOffset, Utc};
|
||||
use chrono::{
|
||||
DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike,
|
||||
|
|
|
@ -6,8 +6,8 @@ mod min_const_generics {
|
|||
use crate::conversion::{AsPyPointer, IntoPyPointer};
|
||||
use crate::types::PySequence;
|
||||
use crate::{
|
||||
ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, PyTryFrom,
|
||||
Python, ToPyObject,
|
||||
ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python,
|
||||
ToPyObject,
|
||||
};
|
||||
|
||||
impl<T, const N: usize> IntoPy<PyObject> for [T; N]
|
||||
|
@ -65,9 +65,9 @@ mod min_const_generics {
|
|||
{
|
||||
// Types that pass `PySequence_Check` usually implement enough of the sequence protocol
|
||||
// to support this function and if not, we will only fail extraction safely.
|
||||
let seq = unsafe {
|
||||
let seq: &PySequence = unsafe {
|
||||
if ffi::PySequence_Check(obj.as_ptr()) != 0 {
|
||||
<PySequence as PyTryFrom>::try_from_unchecked(obj)
|
||||
obj.downcast_unchecked()
|
||||
} else {
|
||||
return Err(PyDowncastError::new(obj, "Sequence").into());
|
||||
}
|
||||
|
@ -187,8 +187,8 @@ mod array_impls {
|
|||
use crate::conversion::{AsPyPointer, IntoPyPointer};
|
||||
use crate::types::PySequence;
|
||||
use crate::{
|
||||
ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, PyTryFrom,
|
||||
Python, ToPyObject,
|
||||
ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python,
|
||||
ToPyObject,
|
||||
};
|
||||
use std::mem::{transmute_copy, ManuallyDrop};
|
||||
|
||||
|
@ -288,9 +288,9 @@ mod array_impls {
|
|||
{
|
||||
// Types that pass `PySequence_Check` usually implement enough of the sequence protocol
|
||||
// to support this function and if not, we will only fail extraction safely.
|
||||
let seq = unsafe {
|
||||
let seq: &PySequence = unsafe {
|
||||
if ffi::PySequence_Check(obj.as_ptr()) != 0 {
|
||||
<PySequence as PyTryFrom>::try_from_unchecked(obj)
|
||||
obj.downcast_unchecked()
|
||||
} else {
|
||||
return Err(PyDowncastError::new(obj, "Sequence").into());
|
||||
}
|
||||
|
|
|
@ -1002,6 +1002,21 @@ impl PyObject {
|
|||
<T as PyTryFrom<'_>>::try_from(self.as_ref(py))
|
||||
}
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type without checking validity.
|
||||
///
|
||||
/// This can cast only to native Python types, not types implemented in Rust. For a more
|
||||
/// flexible alternative, see [`Py::extract`](struct.Py.html#method.extract).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Callers must ensure that the type is valid or risk type confusion.
|
||||
pub unsafe fn downcast_unchecked<'p, T>(&'p self, py: Python<'p>) -> &T
|
||||
where
|
||||
T: PyTryFrom<'p>,
|
||||
{
|
||||
<T as PyTryFrom<'_>>::try_from_unchecked(self.as_ref(py))
|
||||
}
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
#[deprecated(since = "0.18.0", note = "use downcast() instead")]
|
||||
pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError<'_>>
|
||||
|
|
|
@ -780,6 +780,18 @@ impl PyAny {
|
|||
<T as PyTryFrom>::try_from(self)
|
||||
}
|
||||
|
||||
/// Converts this `PyAny` to a concrete Python type without checking validity.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Callers must ensure that the type is valid or risk type confusion.
|
||||
pub unsafe fn downcast_unchecked<'p, T>(&'p self) -> &'p T
|
||||
where
|
||||
T: PyTryFrom<'p>,
|
||||
{
|
||||
<T as PyTryFrom>::try_from_unchecked(self)
|
||||
}
|
||||
|
||||
/// Extracts some type from the Python object.
|
||||
///
|
||||
/// This is a wrapper function around [`FromPyObject::extract()`].
|
||||
|
|
|
@ -4,7 +4,7 @@ use super::PyMapping;
|
|||
use crate::err::{self, PyErr, PyResult};
|
||||
use crate::ffi::Py_ssize_t;
|
||||
use crate::types::{PyAny, PyList};
|
||||
use crate::{ffi, AsPyPointer, PyTryFrom, Python, ToPyObject};
|
||||
use crate::{ffi, AsPyPointer, Python, ToPyObject};
|
||||
#[cfg(not(PyPy))]
|
||||
use crate::{IntoPyPointer, PyObject};
|
||||
use std::ptr::NonNull;
|
||||
|
@ -255,7 +255,7 @@ impl PyDict {
|
|||
|
||||
/// Returns `self` cast as a `PyMapping`.
|
||||
pub fn as_mapping(&self) -> &PyMapping {
|
||||
unsafe { PyMapping::try_from_unchecked(self) }
|
||||
unsafe { self.downcast_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ impl<'v> PyTryFrom<'v> for PyIterator {
|
|||
let value = value.into();
|
||||
unsafe {
|
||||
if ffi::PyIter_Check(value.as_ptr()) != 0 {
|
||||
Ok(<PyIterator as PyTryFrom>::try_from_unchecked(value))
|
||||
Ok(value.downcast_unchecked())
|
||||
} else {
|
||||
Err(PyDowncastError::new(value, "Iterator"))
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::err::{self, PyResult};
|
|||
use crate::ffi::{self, Py_ssize_t};
|
||||
use crate::internal_tricks::get_ssize_index;
|
||||
use crate::types::PySequence;
|
||||
use crate::{AsPyPointer, IntoPyPointer, Py, PyAny, PyObject, PyTryFrom, Python, ToPyObject};
|
||||
use crate::{AsPyPointer, IntoPyPointer, Py, PyAny, PyObject, Python, ToPyObject};
|
||||
|
||||
/// Represents a Python `list`.
|
||||
#[repr(transparent)]
|
||||
|
@ -115,7 +115,7 @@ impl PyList {
|
|||
|
||||
/// Returns `self` cast as a `PySequence`.
|
||||
pub fn as_sequence(&self) -> &PySequence {
|
||||
unsafe { PySequence::try_from_unchecked(self) }
|
||||
unsafe { self.downcast_unchecked() }
|
||||
}
|
||||
|
||||
/// Gets the list item at the specified index.
|
||||
|
|
|
@ -142,7 +142,7 @@ impl<'v> PyTryFrom<'v> for PyMapping {
|
|||
// TODO: surface specific errors in this chain to the user
|
||||
if let Ok(abc) = get_mapping_abc(value.py()) {
|
||||
if value.is_instance(abc).unwrap_or(false) {
|
||||
unsafe { return Ok(<PyMapping as PyTryFrom>::try_from_unchecked(value)) }
|
||||
unsafe { return Ok(value.downcast_unchecked()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -301,9 +301,9 @@ where
|
|||
{
|
||||
// Types that pass `PySequence_Check` usually implement enough of the sequence protocol
|
||||
// to support this function and if not, we will only fail extraction safely.
|
||||
let seq = unsafe {
|
||||
let seq: &PySequence = unsafe {
|
||||
if ffi::PySequence_Check(obj.as_ptr()) != 0 {
|
||||
<PySequence as PyTryFrom>::try_from_unchecked(obj)
|
||||
obj.downcast_unchecked()
|
||||
} else {
|
||||
return Err(PyDowncastError::new(obj, "Sequence").into());
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ impl<'v> PyTryFrom<'v> for PySequence {
|
|||
// TODO: surface specific errors in this chain to the user
|
||||
if let Ok(abc) = get_sequence_abc(value.py()) {
|
||||
if value.is_instance(abc).unwrap_or(false) {
|
||||
unsafe { return Ok(<PySequence as PyTryFrom>::try_from_unchecked(value)) }
|
||||
unsafe { return Ok(value.downcast_unchecked::<PySequence>()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ impl Py<PySequence> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::{PyList, PySequence};
|
||||
use crate::{AsPyPointer, Py, PyObject, PyTryFrom, Python, ToPyObject};
|
||||
use crate::{AsPyPointer, Py, PyObject, Python, ToPyObject};
|
||||
|
||||
fn get_object() -> PyObject {
|
||||
// Convenience function for getting a single unique object
|
||||
|
@ -867,13 +867,13 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_try_from_unchecked() {
|
||||
fn test_seq_downcast_unchecked() {
|
||||
Python::with_gil(|py| {
|
||||
let v = vec!["foo", "bar"];
|
||||
let ob = v.to_object(py);
|
||||
let seq = ob.downcast::<PySequence>(py).unwrap();
|
||||
let type_ptr = seq.as_ref();
|
||||
let seq_from = unsafe { <PySequence as PyTryFrom>::try_from_unchecked(type_ptr) };
|
||||
let seq_from = unsafe { type_ptr.downcast_unchecked::<PySequence>() };
|
||||
assert!(seq_from.list().is_ok());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::internal_tricks::get_ssize_index;
|
|||
use crate::types::PySequence;
|
||||
use crate::{
|
||||
exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyObject,
|
||||
PyResult, PyTryFrom, Python, ToPyObject,
|
||||
PyResult, Python, ToPyObject,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
|
@ -120,7 +120,7 @@ impl PyTuple {
|
|||
|
||||
/// Returns `self` cast as a `PySequence`.
|
||||
pub fn as_sequence(&self) -> &PySequence {
|
||||
unsafe { PySequence::try_from_unchecked(self) }
|
||||
unsafe { self.downcast_unchecked() }
|
||||
}
|
||||
|
||||
/// Takes the slice `self[low:high]` and returns it as a new tuple.
|
||||
|
|
Loading…
Reference in New Issue