Modify AsPyRef::as_ref to return PyRef

This commit is contained in:
kngwyu 2019-02-07 14:27:13 +09:00
parent 22687c3712
commit 01fc1405b0
8 changed files with 89 additions and 55 deletions

View File

@ -165,7 +165,7 @@ where
/// Extract reference to instance from `PyObject`
impl<'a, T> FromPyObject<'a> for &'a T
where
T: PyTryFrom,
T: PyTryFrom<'a>,
{
#[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> {
@ -176,7 +176,7 @@ where
/// Extract mutable reference to instance from `PyObject`
impl<'a, T> FromPyObject<'a> for &'a mut T
where
T: PyTryFrom,
T: PyTryFrom<'a>,
{
#[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a mut T> {
@ -221,33 +221,35 @@ pub trait PyTryInto<T>: Sized {
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryFrom`
pub trait PyTryFrom: Sized {
pub trait PyTryFrom<'v>: Sized {
/// Cast from a concrete Python object type to PyObject.
fn try_from(value: &PyObjectRef) -> Result<&Self, PyDowncastError>;
fn try_from<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_exact(value: &PyObjectRef) -> Result<&Self, PyDowncastError>;
fn try_from_exact<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject.
fn try_from_mut(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>;
fn try_from_mut<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v mut Self, PyDowncastError>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>;
fn try_from_mut_exact<V: Into<&'v PyObjectRef>>(
value: V,
) -> Result<&'v 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;
unsafe fn try_from_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v 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;
unsafe fn try_from_mut_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v mut Self;
}
// TryFrom implies TryInto
impl<U> PyTryInto<U> for PyObjectRef
where
U: PyTryFrom,
U: for<'v> PyTryFrom<'v>,
{
type Error = PyDowncastError;
@ -265,11 +267,12 @@ where
}
}
impl<T> PyTryFrom for T
impl<'v, T> PyTryFrom<'v> for T
where
T: PyTypeInfo,
{
fn try_from(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
fn try_from<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_instance(value) {
Ok(PyTryFrom::try_from_unchecked(value))
@ -279,7 +282,8 @@ where
}
}
fn try_from_exact(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
fn try_from_exact<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_unchecked(value))
@ -289,7 +293,8 @@ where
}
}
fn try_from_mut(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> {
fn try_from_mut<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v mut T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(value))
@ -299,7 +304,10 @@ where
}
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> {
fn try_from_mut_exact<V: Into<&'v PyObjectRef>>(
value: V,
) -> Result<&'v mut T, PyDowncastError> {
let value = value.into();
unsafe {
if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(value))
@ -310,7 +318,8 @@ where
}
#[inline]
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &T {
unsafe fn try_from_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v T {
let value = value.into();
let ptr = if T::OFFSET == 0 {
value as *const _ as *const u8 as *const T
} else {
@ -320,7 +329,8 @@ where
}
#[inline]
unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut T {
unsafe fn try_from_mut_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v mut T {
let value = value.into();
let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T
} else {
@ -357,8 +367,6 @@ impl<T: IntoPyObject> ReturnTypeIntoPyResult for PyResult<T> {
}
}
#[cfg(test)]
mod test {
use super::PyTryFrom;

View File

@ -55,6 +55,15 @@ impl<'a, T> Deref for PyRef<'a, T> {
}
}
impl<'a, T> Into<&'a PyObjectRef> for PyRef<'a, T>
where
T: PyTypeInfo,
{
fn into(self) -> &'a PyObjectRef {
unsafe { &*(self.as_ptr() as *const PyObjectRef) }
}
}
#[derive(Debug)]
pub struct PyRefMut<'a, T> {
inner: &'a mut T,
@ -91,18 +100,27 @@ impl<'a, T> DerefMut for PyRefMut<'a, T> {
}
}
impl<'a, T> Into<&'a PyObjectRef> for PyRefMut<'a, T>
where
T: PyTypeInfo,
{
fn into(self) -> &'a PyObjectRef {
unsafe { &*(self.as_ptr() as *const PyObjectRef) }
}
}
/// Trait implements object reference extraction from python managed pointer.
pub trait AsPyRef<T>: Sized {
/// Return reference to object.
fn as_ref(&self, py: Python) -> &T;
fn as_ref(&self, py: Python) -> PyRef<T>;
/// Return mutable reference to object.
fn as_mut(&mut self, py: Python) -> &mut T;
fn as_mut(&mut self, py: Python) -> PyRefMut<T>;
/// Acquire python gil and call closure with object reference.
fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(Python, &T) -> R,
F: FnOnce(Python, PyRef<T>) -> R,
{
let gil = Python::acquire_gil();
let py = gil.python();
@ -113,7 +131,7 @@ pub trait AsPyRef<T>: Sized {
/// Acquire python gil and call closure with mutable object reference.
fn with_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(Python, &mut T) -> R,
F: FnOnce(Python, PyRefMut<T>) -> R,
{
let gil = Python::acquire_gil();
let py = gil.python();
@ -124,7 +142,7 @@ pub trait AsPyRef<T>: Sized {
fn into_py<F, R>(self, f: F) -> R
where
Self: IntoPyPointer,
F: FnOnce(Python, &T) -> R,
F: FnOnce(Python, PyRef<T>) -> R,
{
let gil = Python::acquire_gil();
let py = gil.python();
@ -137,7 +155,7 @@ pub trait AsPyRef<T>: Sized {
fn into_mut_py<F, R>(mut self, f: F) -> R
where
Self: IntoPyPointer,
F: FnOnce(Python, &mut T) -> R,
F: FnOnce(Python, PyRefMut<T>) -> R,
{
let gil = Python::acquire_gil();
let py = gil.python();
@ -307,12 +325,12 @@ where
T: PyTypeInfo,
{
#[inline]
fn as_ref(&self, py: Python) -> &T {
self.as_ref_dispatch(py)
fn as_ref(&self, py: Python) -> PyRef<T> {
PyRef::new(self.as_ref_dispatch(py))
}
#[inline]
fn as_mut(&mut self, py: Python) -> &mut T {
self.as_mut_dispatch(py)
fn as_mut(&mut self, py: Python) -> PyRefMut<T> {
PyRefMut::new(self.as_mut_dispatch(py))
}
}

View File

@ -7,7 +7,7 @@ use crate::conversion::{
};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::ffi;
use crate::instance::{AsPyRef, PyObjectWithGIL};
use crate::instance::{AsPyRef, PyObjectWithGIL, PyRef, PyRefMut};
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::pythonrun;
use crate::types::{PyDict, PyObjectRef, PyTuple};
@ -154,7 +154,7 @@ impl PyObject {
/// Casts the PyObject to a concrete Python object type.
pub fn cast_as<D>(&self, py: Python) -> Result<&D, PyDowncastError>
where
D: PyTryFrom,
D: for<'v> PyTryFrom<'v>,
{
D::try_from(self.as_ref(py))
}
@ -165,7 +165,7 @@ impl PyObject {
where
D: FromPyObject<'p>,
{
FromPyObject::extract(self.as_ref(py))
FromPyObject::extract(self.as_ref(py).into())
}
/// Retrieves an attribute value.
@ -256,12 +256,12 @@ impl PyObject {
impl AsPyRef<PyObjectRef> for PyObject {
#[inline]
fn as_ref(&self, _py: Python) -> &PyObjectRef {
unsafe { &*(self as *const _ as *const PyObjectRef) }
fn as_ref(&self, _py: Python) -> PyRef<PyObjectRef> {
unsafe { PyRef::new(&*(self as *const _ as *const PyObjectRef)) }
}
#[inline]
fn as_mut(&mut self, _py: Python) -> &mut PyObjectRef {
unsafe { &mut *(self as *mut _ as *mut PyObjectRef) }
fn as_mut(&mut self, _py: Python) -> PyRefMut<PyObjectRef> {
unsafe { PyRefMut::new(&mut *(self as *mut _ as *mut PyObjectRef)) }
}
}

View File

@ -187,7 +187,7 @@ pub trait ObjectProtocol {
/// Casts the PyObject to a concrete Python object type.
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError>
where
D: PyTryFrom,
D: PyTryFrom<'a>,
&'a PyObjectRef: std::convert::From<&'a Self>;
/// Extracts some type from the Python object.
@ -471,10 +471,10 @@ where
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError>
where
D: PyTryFrom,
D: PyTryFrom<'a>,
&'a PyObjectRef: std::convert::From<&'a Self>,
{
D::try_from(self.into())
D::try_from(self)
}
fn extract<'a, D>(&'a self) -> PyResult<D>

View File

@ -85,12 +85,12 @@ impl<'p> Drop for PyIterator<'p> {
mod tests {
use indoc::indoc;
use crate::conversion::{PyTryFrom, ToPyObject};
use crate::conversion::ToPyObject;
use crate::instance::AsPyRef;
use crate::objectprotocol::ObjectProtocol;
use crate::python::Python;
use crate::pythonrun::GILPool;
use crate::types::{PyDict, PyList, PyObjectRef};
use crate::types::{PyDict, PyList};
use crate::GILGuard;
#[test]
@ -98,7 +98,7 @@ mod tests {
let gil_guard = Python::acquire_gil();
let py = gil_guard.python();
let obj = vec![10, 20].to_object(py);
let inst = <PyObjectRef as PyTryFrom>::try_from(obj.as_ref(py)).unwrap();
let inst = obj.as_ref(py);
let mut it = inst.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());
assert_eq!(20, it.next().unwrap().unwrap().extract().unwrap());
@ -119,7 +119,7 @@ mod tests {
{
let gil_guard = Python::acquire_gil();
let py = gil_guard.python();
let inst = <PyObjectRef as PyTryFrom>::try_from(obj.as_ref(py)).unwrap();
let inst = obj.as_ref(py);
let mut it = inst.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());
@ -147,7 +147,7 @@ mod tests {
{
let _pool = GILPool::new();
let inst = <PyObjectRef as PyTryFrom>::try_from(obj.as_ref(py)).unwrap();
let inst = obj.as_ref(py);
let mut it = inst.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());

View File

@ -275,8 +275,9 @@ where
Ok(v)
}
impl PyTryFrom for PySequence {
fn try_from(value: &PyObjectRef) -> Result<&PySequence, PyDowncastError> {
impl<'v> PyTryFrom<'v> for PySequence {
fn try_from<V: Into<&'v PyObjectRef>>(value: V) -> Result<&'v PySequence, PyDowncastError> {
let value = value.into();
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
Ok(<PySequence as PyTryFrom>::try_from_unchecked(value))
@ -286,11 +287,16 @@ impl PyTryFrom for PySequence {
}
}
fn try_from_exact(value: &PyObjectRef) -> Result<&PySequence, PyDowncastError> {
fn try_from_exact<V: Into<&'v PyObjectRef>>(
value: V,
) -> Result<&'v PySequence, PyDowncastError> {
<PySequence as PyTryFrom>::try_from(value)
}
fn try_from_mut(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> {
fn try_from_mut<V: Into<&'v PyObjectRef>>(
value: V,
) -> Result<&'v mut PySequence, PyDowncastError> {
let value = value.into();
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
Ok(<PySequence as PyTryFrom>::try_from_mut_unchecked(value))
@ -300,19 +306,21 @@ impl PyTryFrom for PySequence {
}
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> {
fn try_from_mut_exact<V: Into<&'v PyObjectRef>>(
value: V,
) -> Result<&'v mut PySequence, PyDowncastError> {
<PySequence as PyTryFrom>::try_from_mut(value)
}
#[inline]
unsafe fn try_from_unchecked(value: &PyObjectRef) -> &PySequence {
let ptr = value as *const _ as *const PySequence;
unsafe fn try_from_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v PySequence {
let ptr = value.into() 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;
unsafe fn try_from_mut_unchecked<V: Into<&'v PyObjectRef>>(value: V) -> &'v mut PySequence {
let ptr = value.into() as *const _ as *mut PySequence;
&mut *ptr
}
}

View File

@ -141,7 +141,7 @@ mod test {
let s = "Hello Python";
let py_string = s.to_object(py);
let s2: &str = FromPyObject::extract(py_string.as_ref(py)).unwrap();
let s2: &str = FromPyObject::extract(py_string.as_ref(py).into()).unwrap();
assert_eq!(s, s2);
}

View File

@ -115,7 +115,7 @@ impl<'a> Iterator for PyTupleIterator<'a> {
if self.index < self.slice.len() {
let item = self.slice[self.index].as_ref(self.py);
self.index += 1;
Some(item)
Some(item.into())
} else {
None
}