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` /// Extract reference to instance from `PyObject`
impl<'a, T> FromPyObject<'a> for &'a T impl<'a, T> FromPyObject<'a> for &'a T
where where
T: PyTryFrom, T: PyTryFrom<'a>,
{ {
#[inline] #[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> { default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> {
@ -176,7 +176,7 @@ where
/// Extract mutable reference to instance from `PyObject` /// Extract mutable reference to instance from `PyObject`
impl<'a, T> FromPyObject<'a> for &'a mut T impl<'a, T> FromPyObject<'a> for &'a mut T
where where
T: PyTryFrom, T: PyTryFrom<'a>,
{ {
#[inline] #[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a mut T> { 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. /// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryFrom` /// 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. /// 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. /// 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. /// 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. /// 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 /// Cast a PyObjectRef to a specific type of PyObject. The caller must
/// have already verified the reference is for this type. /// 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 /// Cast a PyObjectRef to a specific type of PyObject. The caller must
/// have already verified the reference is for this type. /// have already verified the reference is for this type.
#[allow(clippy::mut_from_ref)] #[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 // TryFrom implies TryInto
impl<U> PyTryInto<U> for PyObjectRef impl<U> PyTryInto<U> for PyObjectRef
where where
U: PyTryFrom, U: for<'v> PyTryFrom<'v>,
{ {
type Error = PyDowncastError; type Error = PyDowncastError;
@ -265,11 +267,12 @@ where
} }
} }
impl<T> PyTryFrom for T impl<'v, T> PyTryFrom<'v> for T
where where
T: PyTypeInfo, 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 { unsafe {
if T::is_instance(value) { if T::is_instance(value) {
Ok(PyTryFrom::try_from_unchecked(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 { unsafe {
if T::is_exact_instance(value) { if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_unchecked(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 { unsafe {
if T::is_instance(value) { if T::is_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(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 { unsafe {
if T::is_exact_instance(value) { if T::is_exact_instance(value) {
Ok(PyTryFrom::try_from_mut_unchecked(value)) Ok(PyTryFrom::try_from_mut_unchecked(value))
@ -310,7 +318,8 @@ where
} }
#[inline] #[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 { let ptr = if T::OFFSET == 0 {
value as *const _ as *const u8 as *const T value as *const _ as *const u8 as *const T
} else { } else {
@ -320,7 +329,8 @@ where
} }
#[inline] #[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 { let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T value as *const _ as *mut u8 as *mut T
} else { } else {
@ -357,8 +367,6 @@ impl<T: IntoPyObject> ReturnTypeIntoPyResult for PyResult<T> {
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::PyTryFrom; 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)] #[derive(Debug)]
pub struct PyRefMut<'a, T> { pub struct PyRefMut<'a, T> {
inner: &'a mut 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. /// Trait implements object reference extraction from python managed pointer.
pub trait AsPyRef<T>: Sized { pub trait AsPyRef<T>: Sized {
/// Return reference to object. /// Return reference to object.
fn as_ref(&self, py: Python) -> &T; fn as_ref(&self, py: Python) -> PyRef<T>;
/// Return mutable reference to object. /// 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. /// Acquire python gil and call closure with object reference.
fn with<F, R>(&self, f: F) -> R fn with<F, R>(&self, f: F) -> R
where where
F: FnOnce(Python, &T) -> R, F: FnOnce(Python, PyRef<T>) -> R,
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
@ -113,7 +131,7 @@ pub trait AsPyRef<T>: Sized {
/// Acquire python gil and call closure with mutable object reference. /// Acquire python gil and call closure with mutable object reference.
fn with_mut<F, R>(&mut self, f: F) -> R fn with_mut<F, R>(&mut self, f: F) -> R
where where
F: FnOnce(Python, &mut T) -> R, F: FnOnce(Python, PyRefMut<T>) -> R,
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
@ -124,7 +142,7 @@ pub trait AsPyRef<T>: Sized {
fn into_py<F, R>(self, f: F) -> R fn into_py<F, R>(self, f: F) -> R
where where
Self: IntoPyPointer, Self: IntoPyPointer,
F: FnOnce(Python, &T) -> R, F: FnOnce(Python, PyRef<T>) -> R,
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
@ -137,7 +155,7 @@ pub trait AsPyRef<T>: Sized {
fn into_mut_py<F, R>(mut self, f: F) -> R fn into_mut_py<F, R>(mut self, f: F) -> R
where where
Self: IntoPyPointer, Self: IntoPyPointer,
F: FnOnce(Python, &mut T) -> R, F: FnOnce(Python, PyRefMut<T>) -> R,
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
@ -307,12 +325,12 @@ where
T: PyTypeInfo, T: PyTypeInfo,
{ {
#[inline] #[inline]
fn as_ref(&self, py: Python) -> &T { fn as_ref(&self, py: Python) -> PyRef<T> {
self.as_ref_dispatch(py) PyRef::new(self.as_ref_dispatch(py))
} }
#[inline] #[inline]
fn as_mut(&mut self, py: Python) -> &mut T { fn as_mut(&mut self, py: Python) -> PyRefMut<T> {
self.as_mut_dispatch(py) PyRefMut::new(self.as_mut_dispatch(py))
} }
} }

View File

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

View File

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

View File

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

View File

@ -141,7 +141,7 @@ mod test {
let s = "Hello Python"; let s = "Hello Python";
let py_string = s.to_object(py); 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); assert_eq!(s, s2);
} }

View File

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