Merge pull request #294 from ijl/try

PyTryFrom::try_from_unchecked()
This commit is contained in:
Yuji Kanagawa 2018-12-03 23:03:20 +09:00 committed by GitHub
commit 32d6d4e99a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 29 deletions

View file

@ -233,6 +233,15 @@ 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;
/// Cast a PyObjectRef to a specific type of PyObject. The caller must
/// have already verified the reference is for this type.
#[allow(clippy::mut_from_ref)]
unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut Self;
}
// TryFrom implies TryInto
@ -263,12 +272,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 +282,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)
}
@ -293,12 +292,7 @@ where
fn try_from_mut(value: &PyObjectRef) -> Result<&mut 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(&mut *ptr)
Ok(PyTryFrom::try_from_mut_unchecked(value))
} else {
Err(PyDowncastError)
}
@ -308,17 +302,32 @@ where
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut 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(&mut *ptr)
Ok(PyTryFrom::try_from_mut_unchecked(value))
} else {
Err(PyDowncastError)
}
}
}
#[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
}
#[inline]
unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut T {
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
};
&mut *ptr
}
}
/// This trait wraps a T: IntoPyObject into PyResult<T> while PyResult<T> remains PyResult<T>.
@ -347,3 +356,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);
}
}

View file

@ -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)
}
@ -294,8 +293,7 @@ impl PyTryFrom for PySequence {
fn try_from_mut(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> {
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
let ptr = value as *const _ as *mut PySequence;
Ok(&mut *ptr)
Ok(<PySequence as PyTryFrom>::try_from_mut_unchecked(value))
} else {
Err(PyDowncastError)
}
@ -303,7 +301,19 @@ impl PyTryFrom for PySequence {
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> {
PySequence::try_from_mut(value)
<PySequence as PyTryFrom>::try_from_mut(value)
}
#[inline]
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &PySequence {
let ptr = value as *const _ as *const PySequence;
&*ptr
}
#[inline]
unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut PySequence {
let ptr = value as *const _ as *mut PySequence;
&mut *ptr
}
}
@ -629,4 +639,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());
}
}