PyTryFrom::try_from_unchecked()
This allows casting a PyObjectRef to a specific type of PyObject with no overhead.
This commit is contained in:
parent
790a103753
commit
d18ebea1c2
|
@ -233,6 +233,10 @@ pub trait PyTryFrom: Sized {
|
|||
|
||||
/// Cast from a concrete Python object type to PyObject. With exact type check.
|
||||
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>;
|
||||
|
||||
/// Cast a PyObjectRef to a specific type of PyObject. The caller must
|
||||
/// have already verified the reference is for this type.
|
||||
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &Self;
|
||||
}
|
||||
|
||||
// TryFrom implies TryInto
|
||||
|
@ -263,12 +267,7 @@ where
|
|||
fn try_from(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
|
||||
unsafe {
|
||||
if T::is_instance(value) {
|
||||
let ptr = if T::OFFSET == 0 {
|
||||
value as *const _ as *mut u8 as *mut T
|
||||
} else {
|
||||
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
|
||||
};
|
||||
Ok(&*ptr)
|
||||
Ok(PyTryFrom::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError)
|
||||
}
|
||||
|
@ -278,12 +277,7 @@ where
|
|||
fn try_from_exact(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
|
||||
unsafe {
|
||||
if T::is_exact_instance(value) {
|
||||
let ptr = if T::OFFSET == 0 {
|
||||
value as *const _ as *mut u8 as *mut T
|
||||
} else {
|
||||
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
|
||||
};
|
||||
Ok(&*ptr)
|
||||
Ok(PyTryFrom::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError)
|
||||
}
|
||||
|
@ -319,6 +313,16 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &T {
|
||||
let ptr = if T::OFFSET == 0 {
|
||||
value as *const _ as *const u8 as *const T
|
||||
} else {
|
||||
(value.as_ptr() as *const u8).offset(T::OFFSET) as *const T
|
||||
};
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait wraps a T: IntoPyObject into PyResult<T> while PyResult<T> remains PyResult<T>.
|
||||
|
@ -347,3 +351,19 @@ impl<T: IntoPyObject> ReturnTypeIntoPyResult for PyResult<T> {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Python;
|
||||
use crate::types::PyList;
|
||||
use super::PyTryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_try_from_unchecked() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let list = PyList::new(py, &[1, 2, 3]);
|
||||
let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) };
|
||||
assert_eq!(list, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,8 +279,7 @@ impl PyTryFrom for PySequence {
|
|||
fn try_from(value: &PyObjectRef) -> Result<&PySequence, PyDowncastError> {
|
||||
unsafe {
|
||||
if ffi::PySequence_Check(value.as_ptr()) != 0 {
|
||||
let ptr = value as *const _ as *mut PySequence;
|
||||
Ok(&*ptr)
|
||||
Ok(<PySequence as PyTryFrom>::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError)
|
||||
}
|
||||
|
@ -305,6 +304,12 @@ impl PyTryFrom for PySequence {
|
|||
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> {
|
||||
PySequence::try_from_mut(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &PySequence {
|
||||
let ptr = value as *const _ as *const PySequence;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -629,4 +634,16 @@ mod test {
|
|||
.unwrap();
|
||||
assert!(v == b"abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_try_from_unchecked() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = vec!["foo", "bar"];
|
||||
let ob = v.to_object(py);
|
||||
let seq = ob.cast_as::<PySequence>(py).unwrap();
|
||||
let type_ptr = seq.as_ref();
|
||||
let seq_from = unsafe { <PySequence as PyTryFrom>::try_from_unchecked(type_ptr) };
|
||||
assert!(seq_from.list().is_ok());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue