refactor downcast process

This commit is contained in:
Nikolay Kim 2017-07-28 23:19:00 -07:00
parent d78692017e
commit 325070f6c9
31 changed files with 387 additions and 461 deletions

View file

@ -85,20 +85,6 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
f(self.as_ptr())
}
}
impl<'a> _pyo3::IntoPyObject for &'a #cls
{
#[inline]
fn into_object<'p>(self, py: _pyo3::Python) -> _pyo3::PyObject {
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a> _pyo3::IntoPyObject for &'a mut #cls
{
#[inline]
fn into_object<'p>(self, py: _pyo3::Python) -> _pyo3::PyObject {
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a> std::convert::From<&'a mut #cls> for &'a #cls
{
fn from(ob: &'a mut #cls) -> Self {
@ -110,8 +96,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
fn as_ptr(&self) -> *mut ffi::PyObject {
unsafe {
{self as *const _ as *mut u8}
.offset(-<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET)
as *mut ffi::PyObject
.offset(-<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut ffi::PyObject
}
}
}
@ -208,12 +193,6 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
&mut TYPE_OBJECT
}
#[inline]
fn is_instance(ptr: *mut _pyo3::ffi::PyObject) -> bool {
unsafe {_pyo3::ffi::PyObject_TypeCheck(
ptr, <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0}
}
}
impl _pyo3::typeob::PyTypeObject for #cls {
@ -236,89 +215,6 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
}
}
impl _pyo3::PyDowncastFrom for #cls
{
fn try_downcast_from(ob: &_pyo3::PyObjectRef) -> Option<&#cls>
{
unsafe {
let ptr = ob.as_ptr();
let checked = ffi::PyObject_TypeCheck(
ptr, <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0;
if checked {
let ptr = (ptr as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
Some(ptr.as_ref().unwrap())
} else {
None
}
}
}
fn try_exact_downcast_from(ob: &_pyo3::PyObjectRef) -> Option<&#cls>
{
unsafe {
let ptr = ob.as_ptr();
if (*ptr).ob_type == <#cls as _pyo3::typeob::PyTypeInfo>::type_object()
{
let ptr = (ptr as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
Some(ptr.as_ref().unwrap())
} else {
None
}
}
}
#[inline]
unsafe fn unchecked_downcast_from(ob: &_pyo3::PyObjectRef) -> &Self
{
let ptr = (ob.as_ptr() as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
&*ptr
}
#[inline]
unsafe fn unchecked_mut_downcast_from(ob: &_pyo3::PyObjectRef) -> &mut Self
{
let ptr = (ob.as_ptr() as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
&mut *ptr
}
}
impl _pyo3::PyMutDowncastFrom for #cls
{
fn try_mut_downcast_from(ob: &mut _pyo3::PyObjectRef) -> Option<&mut #cls>
{
unsafe {
let ptr = ob.as_ptr();
let checked = ffi::PyObject_TypeCheck(
ptr, <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0;
if checked {
let ptr = (ptr as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
Some(ptr.as_mut().unwrap())
} else {
None
}
}
}
fn try_mut_exact_downcast_from(ob: &mut _pyo3::PyObjectRef) -> Option<&mut #cls>
{
unsafe {
let ptr = ob.as_ptr();
if (*ptr).ob_type == <#cls as _pyo3::typeob::PyTypeInfo>::type_object()
{
let ptr = (ptr as *mut u8)
.offset(<#cls as _pyo3::typeob::PyTypeInfo>::OFFSET) as *mut #cls;
Some(ptr.as_mut().unwrap())
} else {
None
}
}
}
}
#extra
}
}

View file

@ -3,10 +3,10 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
//! Python argument parsing
use ffi;
use err::PyResult;
use python::{Python, PyDowncastFrom};
use python::Python;
use conversion::PyTryFrom;
use objects::{PyObjectRef, PyTuple, PyDict, PyString, exc};
#[derive(Debug)]
@ -80,8 +80,8 @@ pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
if !accept_kwargs && used_keywords != nkeywords {
// check for extraneous keyword arguments
for item in kwargs.unwrap().items().iter() {
let item = PyTuple::downcast_from(item)?;
let key = PyString::downcast_from(item.get_item(0))?.to_string()?;
let item = PyTuple::try_from(item)?;
let key = PyString::try_from(item.get_item(0))?.to_string()?;
if !params.iter().any(|p| p.name == key) {
return Err(exc::TypeError::new(
format!("'{}' is an invalid keyword argument for this function", key)));

View file

@ -10,7 +10,6 @@
use ffi;
use err::PyResult;
use python::PyDowncastFrom;
use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
@ -20,7 +19,7 @@ use class::methods::PyMethodDef;
///
/// Each method in this trait corresponds to Python async/await implementation.
#[allow(unused_variables)]
pub trait PyAsyncProtocol<'p>: PyTypeInfo + PyDowncastFrom {
pub trait PyAsyncProtocol<'p>: PyTypeInfo {
fn __await__(&'p self)
-> Self::Result where Self: PyAsyncAwaitProtocol<'p> { unimplemented!() }

View file

@ -12,7 +12,7 @@ use std::os::raw::c_int;
use ::CompareOp;
use ffi;
use err::{PyErr, PyResult};
use python::{Python, IntoPyPointer, PyDowncastFrom};
use python::{Python, IntoPyPointer};
use objects::{exc, PyObjectRef};
use typeob::PyTypeInfo;
use conversion::{FromPyObject, IntoPyObject};
@ -23,7 +23,7 @@ use class::methods::PyMethodDef;
/// Basic python class customization
#[allow(unused_variables)]
pub trait PyObjectProtocol<'p>: PyTypeInfo + PyDowncastFrom + Sized + 'static {
pub trait PyObjectProtocol<'p>: PyTypeInfo {
fn __getattr__(&'p self, name: Self::Name)
-> Self::Result where Self: PyObjectGetAttrProtocol<'p> {unimplemented!()}
@ -351,14 +351,14 @@ impl<'p, T> PyObjectRichcmpProtocolImpl for T where T: PyObjectProtocol<'p>
}
}
impl<T> PyObjectRichcmpProtocolImpl for T
where T: for<'p> PyObjectRichcmpProtocol<'p> + PyDowncastFrom
where T: for<'p> PyObjectRichcmpProtocol<'p>
{
#[inline]
fn tp_richcompare() -> Option<ffi::richcmpfunc> {
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
op: c_int) -> *mut ffi::PyObject
where T: for<'p> PyObjectRichcmpProtocol<'p> + PyDowncastFrom
where T: for<'p> PyObjectRichcmpProtocol<'p>
{
let _pool = ::GILPool::new();
let py = Python::assume_gil_acquired();

View file

@ -10,7 +10,6 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use typeob::PyTypeInfo;
use python::PyDowncastFrom;
use callback::UnitCallbackConverter;
@ -19,7 +18,7 @@ use callback::UnitCallbackConverter;
/// more information on buffer protocol can be found
/// https://docs.python.org/3/c-api/buffer.html
#[allow(unused_variables)]
pub trait PyBufferProtocol<'p> : PyTypeInfo + PyDowncastFrom
pub trait PyBufferProtocol<'p> : PyTypeInfo
{
fn bf_getbuffer(&'p self,
view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result

View file

@ -9,7 +9,6 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use python::PyDowncastFrom;
use objects::{PyType, PyObjectRef};
use callback::{PyObjectCallbackConverter, UnitCallbackConverter};
use typeob::PyTypeInfo;
@ -19,7 +18,7 @@ use conversion::{IntoPyObject, FromPyObject};
/// Descriptor interface
#[allow(unused_variables)]
pub trait PyDescrProtocol<'p>: PyTypeInfo + PyDowncastFrom {
pub trait PyDescrProtocol<'p>: PyTypeInfo {
fn __get__(&'p self, instance: &'p PyObjectRef, owner: Option<&'p PyType>)
-> Self::Result where Self: PyDescrGetProtocol<'p> { unimplemented!() }

View file

@ -6,14 +6,14 @@
use std::os::raw::{c_int, c_void};
use ffi;
use python::{Python, ToPyPointer, PyDowncastFrom};
use python::{Python, ToPyPointer};
use typeob::PyTypeInfo;
pub struct PyTraverseError(c_int);
/// GC support
#[allow(unused_variables)]
pub trait PyGCProtocol<'p> : PyTypeInfo + PyDowncastFrom {
pub trait PyGCProtocol<'p> : PyTypeInfo {
fn __traverse__(&'p self, visit: PyVisit)
-> Result<(), PyTraverseError> { unimplemented!() }

View file

@ -6,7 +6,7 @@ use std::ptr;
use ffi;
use err::PyResult;
use python::{Python, PyDowncastFrom, IntoPyPointer};
use python::{Python, IntoPyPointer};
use typeob::PyTypeInfo;
use conversion::IntoPyObject;
use callback::{CallbackConverter, PyObjectCallbackConverter};
@ -17,7 +17,7 @@ use callback::{CallbackConverter, PyObjectCallbackConverter};
/// more information
/// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter
#[allow(unused_variables)]
pub trait PyIterProtocol<'p> : PyTypeInfo + PyDowncastFrom {
pub trait PyIterProtocol<'p> : PyTypeInfo {
fn __iter__(&'p mut self)
-> Self::Result where Self: PyIterIterProtocol<'p> { unimplemented!() }

View file

@ -8,7 +8,7 @@ macro_rules! py_unary_func {
};
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $ret_type:ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
let _pool = $crate::GILPool::new();
let py = $crate::Python::assume_gil_acquired();
@ -26,7 +26,7 @@ macro_rules! py_unary_func {
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
-> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
let _pool = $crate::GILPool::new();
@ -46,7 +46,7 @@ macro_rules! py_len_func {
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
-> $crate::ffi::Py_ssize_t
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
let _pool = $crate::GILPool::new();
let py = Python::assume_gil_acquired();
@ -69,7 +69,7 @@ macro_rules! py_binary_func{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject) -> $return
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
let _pool = $crate::GILPool::new();
@ -94,7 +94,7 @@ macro_rules! py_binary_num_func{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
let _pool = $crate::GILPool::new();
@ -122,7 +122,7 @@ macro_rules! py_binary_self_func{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
@ -158,7 +158,7 @@ macro_rules! py_ssizearg_func {
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: $crate::ffi::Py_ssize_t) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
let _pool = $crate::GILPool::new();
let py = $crate::Python::assume_gil_acquired();
@ -180,7 +180,7 @@ macro_rules! py_ternary_func{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject,
arg1: *mut $crate::ffi::PyObject,
arg2: *mut $crate::ffi::PyObject) -> $return_type
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
@ -211,7 +211,7 @@ macro_rules! py_ternary_num_func{
unsafe extern "C" fn wrap<T>(arg1: *mut $crate::ffi::PyObject,
arg2: *mut $crate::ffi::PyObject,
arg3: *mut $crate::ffi::PyObject) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
@ -374,7 +374,7 @@ macro_rules! py_func_set_del{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject,
name: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject) -> $crate::c_int
where T: for<'p> $trait<'p> + for<'p> $trait2<'p> + $crate::PyDowncastFrom
where T: for<'p> $trait<'p> + for<'p> $trait2<'p>
{
use $crate::ObjectProtocol;

View file

@ -5,7 +5,7 @@
use ffi;
use err::{PyErr, PyResult};
use python::{Python, PyDowncastFrom};
use python::Python;
use objects::exc;
use callback::{PyObjectCallbackConverter, LenResultConverter};
use conversion::{IntoPyObject, FromPyObject};
@ -15,7 +15,7 @@ use class::methods::PyMethodDef;
/// Mapping interface
#[allow(unused_variables)]
pub trait PyMappingProtocol<'p>: PyTypeInfo + PyDowncastFrom + Sized + 'static {
pub trait PyMappingProtocol<'p>: PyTypeInfo {
fn __len__(&'p self)
-> Self::Result where Self: PyMappingLenProtocol<'p> {unimplemented!()}

View file

@ -9,11 +9,11 @@ use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
use class::basic::PyObjectProtocolImpl;
use {IntoPyObject, FromPyObject, PyDowncastFrom};
use {IntoPyObject, FromPyObject};
/// Number interface
#[allow(unused_variables)]
pub trait PyNumberProtocol<'p>: PyTypeInfo + PyDowncastFrom {
pub trait PyNumberProtocol<'p>: PyTypeInfo {
fn __add__(lhs: Self::Left, rhs: Self::Right)
-> Self::Result where Self: PyNumberAddProtocol<'p> { unimplemented!() }

View file

@ -6,7 +6,7 @@
use std::os::raw::c_int;
use ffi;
use python::{Python, PyDowncastFrom};
use python::Python;
use err::{PyErr, PyResult};
use objects::{exc, PyObjectRef};
use objectprotocol::ObjectProtocol;
@ -17,7 +17,7 @@ use conversion::{IntoPyObject, FromPyObject};
/// Sequece interface
#[allow(unused_variables)]
pub trait PySequenceProtocol<'p>: PyTypeInfo + PyDowncastFrom
pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized
{
fn __len__(&'p self) -> Self::Result
where Self: PySequenceLenProtocol<'p> { unimplemented!() }

View file

@ -1,9 +1,10 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
//! This module contains some conversion traits
use ffi;
use err::PyResult;
use python::{Python, ToPyPointer, PyDowncastFrom};
use err::{PyResult, PyDowncastError};
use python::{Python, ToPyPointer};
use object::PyObject;
use objects::{PyObjectRef, PyTuple};
use typeob::PyTypeInfo;
@ -115,15 +116,6 @@ impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
}
}
impl <'a, T: ?Sized> ToBorrowedObject for &'a T where T: ToBorrowedObject {
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
<T as ToBorrowedObject>::with_borrowed_ptr(*self, py, f)
}
}
/// `Option::Some<T>` is converted like `T`.
/// `Option::None` is converted to Python `None`.
@ -157,15 +149,29 @@ impl IntoPyObject for () {
py.None()
}
}
impl<'a, T> IntoPyObject for &'a T where T: ToPyPointer
{
#[inline]
fn into_object<'p>(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a, T> IntoPyObject for &'a mut T where T: ToPyPointer
{
#[inline]
fn into_object<'p>(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
/// Extract reference to instance from `PyObject`
impl<'a, T> FromPyObject<'a> for &'a T
where T: PyTypeInfo + PyDowncastFrom
where T: PyTypeInfo
{
#[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T>
{
Ok(PyDowncastFrom::downcast_from(ob)?)
Ok(T::try_from(ob)?)
}
}
@ -183,3 +189,128 @@ impl<'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'sour
}
}
}
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryInto`
pub trait PyTryInto<T>: Sized {
/// The type returned in the event of a conversion error.
type Error;
/// Cast from PyObject to a concrete Python object type.
fn try_into(&self) -> Result<&T, Self::Error>;
/// Cast from PyObject to a concrete Python object type. With exact type check.
fn try_into_exact(&self) -> Result<&T, Self::Error>;
/// Cast from PyObject to a concrete Python object type.
fn try_into_mut(&self) -> Result<&mut T, Self::Error>;
/// Cast from PyObject to a concrete Python object type. With exact type check.
fn try_into_mut_exact(&self) -> Result<&mut T, Self::Error>;
}
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryFrom`
pub trait PyTryFrom: Sized {
/// The type returned in the event of a conversion error.
type Error;
/// Cast from a concrete Python object type to PyObject.
fn try_from(value: &PyObjectRef) -> Result<&Self, Self::Error>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_exact(value: &PyObjectRef) -> Result<&Self, Self::Error>;
/// Cast from a concrete Python object type to PyObject.
fn try_from_mut(value: &PyObjectRef) -> Result<&mut Self, Self::Error>;
/// Cast from a concrete Python object type to PyObject. With exact type check.
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut Self, Self::Error>;
}
// TryFrom implies TryInto
impl<U> PyTryInto<U> for PyObjectRef where U: PyTryFrom
{
type Error = U::Error;
fn try_into(&self) -> Result<&U, U::Error> {
U::try_from(self)
}
fn try_into_exact(&self) -> Result<&U, U::Error> {
U::try_from_exact(self)
}
fn try_into_mut(&self) -> Result<&mut U, U::Error> {
U::try_from_mut(self)
}
fn try_into_mut_exact(&self) -> Result<&mut U, U::Error> {
U::try_from_mut_exact(self)
}
}
impl<T> PyTryFrom for T
where T: PyTypeInfo
{
type Error = PyDowncastError;
fn try_from(value: &PyObjectRef) -> Result<&T, Self::Error> {
unsafe {
if T::is_instance(value.as_ptr()) {
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)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_exact(value: &PyObjectRef) -> Result<&T, Self::Error> {
unsafe {
if T::is_exact_instance(value.as_ptr()) {
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)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut(value: &PyObjectRef) -> Result<&mut T, Self::Error> {
unsafe {
if T::is_instance(value.as_ptr()) {
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)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut T, Self::Error> {
unsafe {
if T::is_exact_instance(value.as_ptr()) {
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)
} else {
Err(PyDowncastError)
}
}
}
}

View file

@ -6,12 +6,12 @@ use std::marker::PhantomData;
use ffi;
use pythonrun;
use err::{PyResult, PyErr, PyDowncastError};
use err::{PyResult, PyErr};
use object::PyObject;
use objects::PyObjectRef;
use objectprotocol::ObjectProtocol;
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
use python::{Python, IntoPyPointer, ToPyPointer, PyDowncastInto, PyDowncastFrom};
use python::{Python, IntoPyPointer, ToPyPointer};
use typeob::{PyTypeInfo, PyObjectAlloc};
@ -175,7 +175,7 @@ impl<T> Py<T> where T: PyTypeInfo,
/// Returns references to `T`
pub fn new_ref<F>(py: Python, f: F) -> PyResult<&T>
where F: FnOnce(::PyToken) -> T,
T: PyObjectAlloc<T> + PyDowncastFrom
T: PyObjectAlloc<T>
{
let ob = f(PyToken(PhantomData));
@ -189,7 +189,7 @@ impl<T> Py<T> where T: PyTypeInfo,
/// Returns mutable references to `T`
pub fn new_mut<F>(py: Python, f: F) -> PyResult<&mut T>
where F: FnOnce(::PyToken) -> T,
T: PyObjectAlloc<T> + PyDowncastFrom
T: PyObjectAlloc<T>
{
let ob = f(PyToken(PhantomData));
@ -323,45 +323,6 @@ impl<'a, T> std::convert::From<&'a mut T> for PyObject
}
}
impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
{
fn downcast_into<I>(_py: Python, ob: I) -> Result<Self, PyDowncastError>
where I: IntoPyPointer
{
unsafe{
let ptr = ob.into_ptr();
if T::is_instance(ptr) {
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError)
}
}
}
fn downcast_into_from_ptr(_py: Python, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError>
{
unsafe{
if T::is_instance(ptr) {
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError)
}
}
}
fn unchecked_downcast_into<I>(ob: I) -> Self
where I: IntoPyPointer
{
unsafe{
Py::from_owned_ptr(ob.into_ptr())
}
}
}
impl<'a, T> FromPyObject<'a> for Py<T> where T: ToPyPointer + FromPyObject<'a>
{
/// Extracts `Self` from the source `PyObject`.

View file

@ -1,4 +1,4 @@
#![feature(specialization, proc_macro, const_fn)]
#![feature(specialization, proc_macro, const_fn, try_from)]
//! Rust bindings to the Python interpreter.
//!
@ -154,11 +154,10 @@ pub use err::{PyErr, PyErrValue, PyResult, PyDowncastError, PyErrArguments};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use object::PyObject;
pub use python::{Python, ToPyPointer, IntoPyPointer,
PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto};
pub use python::{Python, ToPyPointer, IntoPyPointer};
pub use pythonrun::{GILGuard, GILPool, prepare_freethreaded_python, prepare_pyo3_library};
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
pub use conversion::{FromPyObject, RefFromPyObject,
pub use conversion::{FromPyObject, RefFromPyObject, PyTryFrom, PyTryInto,
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple};
pub mod class;
pub use class::*;

View file

@ -4,10 +4,10 @@ use std;
use ffi;
use pythonrun;
use err::{PyErr, PyResult};
use err::{PyErr, PyResult, PyDowncastError};
use instance::{AsPyRef, PyObjectWithToken};
use objects::{PyObjectRef, PyDict};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple, FromPyObject};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple, FromPyObject, PyTryFrom};
use python::{Python, ToPyPointer, IntoPyPointer};
@ -151,10 +151,10 @@ impl PyObject {
/// Casts the PyObject to a concrete Python object type.
#[inline]
pub fn cast_as<D>(&self, py: Python) -> Option<&D>
where D: ::PyDowncastFrom
pub fn cast_as<D>(&self, py: Python) -> Result<&D, <D as PyTryFrom>::Error>
where D: PyTryFrom<Error=PyDowncastError>
{
<D as ::PyDowncastFrom>::try_downcast_from(self.as_ref(py))
D::try_from(self.as_ref(py))
}
/// Extracts some type from the Python object.
@ -283,14 +283,6 @@ impl IntoPyObject for PyObject
}
}
impl<'a> IntoPyObject for &'a PyObject
{
#[inline]
fn into_object(self, py: Python) -> PyObject {
unsafe {PyObject::from_borrowed_ptr(py, self.as_ptr())}
}
}
impl<'a> FromPyObject<'a> for PyObject
{
#[inline]

View file

@ -5,11 +5,11 @@ use std::cmp::Ordering;
use std::os::raw::c_int;
use ffi;
use err::{self, PyErr, PyResult};
use python::{Python, ToPyPointer, PyDowncastFrom};
use err::{self, PyErr, PyResult, PyDowncastError};
use python::{Python, ToPyPointer};
use object::PyObject;
use objects::{PyObjectRef, PyDict, PyString, PyIterator, PyType};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyTuple, FromPyObject};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyTuple, FromPyObject, PyTryFrom};
use instance::PyObjectWithToken;
use typeob::PyTypeInfo;
@ -124,12 +124,11 @@ pub trait ObjectProtocol {
/// Gets the Python super object for this object.
/// This is equivalent to the Python expression: 'super()'
fn get_super(&self) -> &<Self as PyTypeInfo>::BaseType
where Self: PyTypeInfo, <Self as PyTypeInfo>::BaseType: PyDowncastFrom;
fn get_super(&self) -> &<Self as PyTypeInfo>::BaseType where Self: PyTypeInfo;
/// Casts the PyObject to a concrete Python object type.
fn cast_as<'a, D>(&'a self) -> Option<&'a D>
where D: PyDowncastFrom,
fn cast_as<'a, D>(&'a self) -> Result<&'a D, <D as PyTryFrom>::Error>
where D: PyTryFrom<Error=PyDowncastError>,
&'a PyObjectRef: std::convert::From<&'a Self>;
/// Extracts some type from the Python object.
@ -357,18 +356,17 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
}
}
fn get_super(&self) -> &<Self as PyTypeInfo>::BaseType
where Self: PyTypeInfo, <Self as PyTypeInfo>::BaseType: PyDowncastFrom
fn get_super(&self) -> &<Self as PyTypeInfo>::BaseType where Self: PyTypeInfo
{
unsafe { self.py().cast_from_borrowed_ptr(self.as_ptr()) }
}
#[inline]
fn cast_as<'a, D>(&'a self) -> Option<&'a D>
where D: PyDowncastFrom,
&'a PyObjectRef: std::convert::From<&'a Self>
fn cast_as<'a, D>(&'a self) -> Result<&'a D, <D as PyTryFrom>::Error>
where D: PyTryFrom<Error=PyDowncastError>,
&'a PyObjectRef: std::convert::From<&'a Self>
{
<D as PyDowncastFrom>::try_downcast_from(self.into())
D::try_from(self.into())
}
#[inline]
@ -393,8 +391,8 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
#[cfg(test)]
mod test {
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use python::Python;
use conversion::{ToPyObject, PyTryFrom};
use objects::PyString;
#[test]
@ -402,7 +400,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "Hello\n".to_object(py);
let s = PyString::downcast_from(v.as_ref(py)).unwrap();
let s = PyString::try_from(v.as_ref(py)).unwrap();
assert_eq!(format!("{:?}", s), "'Hello\\n'");
}
@ -411,7 +409,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "Hello\n".to_object(py);
let s = PyString::downcast_from(v.as_ref(py)).unwrap();
let s = PyString::try_from(v.as_ref(py)).unwrap();
assert_eq!(format!("{}", s), "Hello\n");
}
}

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use ffi;
use object::PyObject;
use python::{ToPyPointer, Python, PyDowncastFrom};
use conversion::{ToPyObject, IntoPyObject, ToBorrowedObject};
use python::{Python, ToPyPointer};
use conversion::{ToPyObject, IntoPyObject, ToBorrowedObject, PyTryFrom};
/// Represents a Python `bool`.
pub struct PyBool(PyObject);
@ -59,7 +59,7 @@ impl IntoPyObject for bool {
///
/// Fails with `TypeError` if the input is not a Python `bool`.
pyobject_extract!(py, obj to bool => {
Ok(PyBool::downcast_from(obj)?.is_true())
Ok(PyBool::try_from(obj)?.is_true())
});

View file

@ -222,9 +222,9 @@ mod test {
use std::collections::{BTreeMap, HashMap};
use python::Python;
use instance::AsPyRef;
use conversion::{ToPyObject, IntoPyObject};
use conversion::{PyTryFrom, ToPyObject, IntoPyObject};
use objects::{PyDict, PyTuple};
use {PyDowncastFrom, ObjectProtocol};
use ObjectProtocol;
#[test]
fn test_new() {
@ -254,11 +254,11 @@ mod test {
let py = gil.python();
let mut v = HashMap::new();
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert_eq!(0, dict.len());
v.insert(7, 32);
let ob = v.to_object(py);
let dict2 = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict2 = PyDict::try_from(ob.as_ref(py)).unwrap();
assert_eq!(1, dict2.len());
}
@ -269,7 +269,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert_eq!(true, dict.contains(7i32).unwrap());
assert_eq!(false, dict.contains(8i32).unwrap());
}
@ -281,7 +281,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert_eq!(32, dict.get_item(7i32).unwrap().extract::<i32>().unwrap());
assert_eq!(None, dict.get_item(8i32));
}
@ -293,7 +293,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert!(dict.set_item(7i32, 42i32).is_ok()); // change
assert!(dict.set_item(8i32, 123i32).is_ok()); // insert
assert_eq!(42i32, dict.get_item(7i32).unwrap().extract::<i32>().unwrap());
@ -325,7 +325,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert!(dict.set_item(7i32, 42i32).is_ok()); // change
assert!(dict.set_item(8i32, 123i32).is_ok()); // insert
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
@ -339,7 +339,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert!(dict.del_item(7i32).is_ok());
assert_eq!(0, dict.len());
assert_eq!(None, dict.get_item(7i32));
@ -352,7 +352,7 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
assert!(dict.del_item(7i32).is_ok()); // change
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
}
@ -366,7 +366,7 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
@ -388,7 +388,7 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
for el in dict.keys().iter() {
@ -406,7 +406,7 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut values_sum = 0;
for el in dict.values().iter() {
@ -424,7 +424,7 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
@ -445,7 +445,7 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
let dict = PyDict::try_from(ob.as_ref(py)).unwrap();
let mut key_sum = 0;
let mut value_sum = 0;
for (key, value) in dict.iter() {
@ -465,7 +465,7 @@ mod test {
map.insert(1, 1);
let m = map.to_object(py);
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
@ -480,7 +480,7 @@ mod test {
map.insert(1, 1);
let m = map.to_object(py);
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
@ -495,7 +495,7 @@ mod test {
map.insert(1, 1);
let m = map.into_object(py);
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
@ -510,7 +510,7 @@ mod test {
map.insert(1, 1);
let m = map.into_object(py);
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);

View file

@ -61,8 +61,8 @@ impl <'p> Iterator for PyIterator<'p> {
#[cfg(test)]
mod tests {
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use python::Python;
use conversion::{PyTryFrom, ToPyObject};
use objects::PyObjectRef;
use objectprotocol::ObjectProtocol;
@ -71,7 +71,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::downcast_from(obj.as_ref(py)).unwrap();
let inst = PyObjectRef::try_from(obj.as_ref(py)).unwrap();
let mut it = inst.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());
assert_eq!(20, it.next().unwrap().unwrap().extract().unwrap());

View file

@ -165,8 +165,8 @@ impl <T> IntoPyObject for Vec<T> where T: IntoPyObject + ToPyObject {
#[cfg(test)]
mod test {
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use python::Python;
use conversion::{ToPyObject, PyTryFrom};
use objects::PyList;
use objectprotocol::ObjectProtocol;
@ -188,7 +188,7 @@ mod test {
let py = gil.python();
let v = vec![1,2,3,4];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
assert_eq!(4, list.len());
}
@ -198,7 +198,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
@ -211,7 +211,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
assert_eq!(2, list.get_parked_item(0).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_parked_item(1).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_parked_item(2).extract::<i32>(py).unwrap());
@ -224,7 +224,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
let val = 42i32.to_object(py);
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
list.set_item(0, val).unwrap();
@ -239,7 +239,7 @@ mod test {
let py = gil.python();
let v = vec![2];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
let none = py.None();
cnt = none.get_refcnt();
list.set_item(0, none).unwrap();
@ -257,7 +257,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
let val = 42i32.to_object(py);
assert_eq!(4, list.len());
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
@ -291,7 +291,7 @@ mod test {
let py = gil.python();
let v = vec![2];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
list.append(3).unwrap();
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
@ -321,7 +321,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
let mut idx = 0;
for el in list.iter() {
assert_eq!(v[idx], el.extract::<i32>().unwrap());
@ -336,7 +336,7 @@ mod test {
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let list = PyList::try_from(ob.as_ref(py)).unwrap();
let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
assert_eq!(v, v2);
}

View file

@ -34,31 +34,6 @@ pub use self::num2::{PyInt, PyLong};
macro_rules! pyobject_downcast(
($name: ident, $checkfunction: ident) => (
impl $crate::python::PyDowncastFrom for $name
{
fn try_downcast_from(ob: &$crate::PyObjectRef) -> Option<&$name>
{
use $crate::ToPyPointer;
unsafe {
if $crate::ffi::$checkfunction(ob.as_ptr()) > 0 {
Some($crate::std::mem::transmute(ob))
} else {
None
}
}
}
unsafe fn unchecked_downcast_from(ob: &$crate::PyObjectRef) -> &Self
{
$crate::std::mem::transmute(ob)
}
unsafe fn unchecked_mut_downcast_from(ob: &$crate::PyObjectRef) -> &mut Self
{
#[allow(mutable_transmutes)]
$crate::std::mem::transmute(ob)
}
}
impl<'a> $crate::FromPyObject<'a> for &'a $name
{
/// Extracts `Self` from the source `PyObject`.
@ -108,24 +83,6 @@ macro_rules! pyobject_nativetype(
self.0.as_ptr()
}
}
impl $crate::python::IntoPyPointer for $name {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn into_ptr(self) -> *mut $crate::ffi::PyObject {
let ptr = self.0.as_ptr();
unsafe { $crate::ffi::Py_INCREF(ptr); }
ptr
}
}
impl<'a> $crate::python::IntoPyPointer for &'a $name {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn into_ptr(self) -> *mut $crate::ffi::PyObject {
let ptr = self.0.as_ptr();
unsafe { $crate::ffi::Py_INCREF(ptr); }
ptr
}
}
impl PartialEq for $name {
#[inline]
fn eq(&self, o: &$name) -> bool {
@ -149,7 +106,7 @@ macro_rules! pyobject_nativetype(
unsafe fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
&mut $crate::ffi::$typeobject
}
#[inline]
fn is_instance(ptr: *mut $crate::ffi::PyObject) -> bool {
#[allow(unused_unsafe)]
unsafe { $crate::ffi::$checkfunction(ptr) > 0 }
@ -184,14 +141,6 @@ macro_rules! pyobject_nativetype(
}
}
impl<'a> $crate::IntoPyObject for &'a $name
{
#[inline]
fn into_object(self, py: $crate::Python) -> $crate::PyObject {
unsafe { $crate::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl $crate::std::fmt::Debug for $name {
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>

View file

@ -1,12 +1,14 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use buffer;
use ffi::{self, Py_ssize_t};
use err::{self, PyErr, PyResult};
use err::{self, PyErr, PyResult, PyDowncastError};
use object::PyObject;
use instance::PyObjectWithToken;
use python::{ToPyPointer, PyDowncastFrom};
use conversion::{FromPyObject, ToBorrowedObject};
use python::ToPyPointer;
use conversion::{FromPyObject, ToBorrowedObject, PyTryFrom};
use objects::{PyObjectRef, PyList, PyTuple};
use objectprotocol::ObjectProtocol;
@ -34,8 +36,9 @@ impl PySequence {
#[inline]
pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> {
unsafe {
self.py().cast_from_ptr_or_err::<PySequence>(
ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))
let ptr = self.py().cast_from_ptr_or_err::<PyObjectRef>(
ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))?;
Ok(std::mem::transmute(ptr))
}
}
@ -45,8 +48,9 @@ impl PySequence {
#[inline]
pub fn repeat(&self, count: isize) -> PyResult<&PySequence> {
unsafe {
self.py().cast_from_ptr_or_err::<PySequence>(
ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))
let ptr = self.py().cast_from_ptr_or_err::<PyObjectRef>(
ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))?;
Ok(std::mem::transmute(ptr))
}
}
@ -232,7 +236,7 @@ impl <'source, T> FromPyObject<'source> for Vec<T>
fn extract_sequence<'s, T>(obj: &'s PyObjectRef) -> PyResult<Vec<T>> where T: FromPyObject<'s>
{
let seq = PySequence::downcast_from(obj)?;
let seq = PySequence::try_from(obj)?;
let mut v = Vec::new();
for item in try!(seq.iter()) {
let item = try!(item);
@ -241,12 +245,48 @@ fn extract_sequence<'s, T>(obj: &'s PyObjectRef) -> PyResult<Vec<T>> where T: Fr
Ok(v)
}
impl PyTryFrom for PySequence
{
type Error = PyDowncastError;
fn try_from(value: &PyObjectRef) -> Result<&PySequence, Self::Error> {
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
let ptr = value as *const _ as *mut u8 as *mut PySequence;
Ok(&*ptr)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_exact(value: &PyObjectRef) -> Result<&PySequence, Self::Error> {
PySequence::try_from(value)
}
fn try_from_mut(value: &PyObjectRef) -> Result<&mut PySequence, Self::Error> {
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
let ptr = value as *const _ as *mut u8 as *mut PySequence;
Ok(&mut *ptr)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut PySequence, Self::Error> {
PySequence::try_from_mut(value)
}
}
#[cfg(test)]
mod test {
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objects::{PySequence};
use python::Python;
use conversion::{PyTryFrom, ToPyObject};
use objects::PySequence;
use objectprotocol::ObjectProtocol;
#[test]
@ -254,7 +294,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = 42i32;
assert!(PySequence::downcast_from(v.to_object(py).as_ref(py)).is_err());
assert!(PySequence::try_from(v.to_object(py).as_ref(py)).is_err());
}
#[test]
@ -262,7 +302,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "London Calling";
assert!(PySequence::downcast_from(v.to_object(py).as_ref(py)).is_ok());
assert!(PySequence::try_from(v.to_object(py).as_ref(py)).is_ok());
}
#[test]
fn test_seq_empty() {
@ -499,7 +539,7 @@ mod test {
let py = gil.python();
let v = "foo";
let ob = v.to_object(py);
let seq = PySequence::downcast_from(ob.as_ref(py)).unwrap();
let seq = PySequence::try_from(ob.as_ref(py)).unwrap();
assert!(seq.list().is_ok());
}

View file

@ -144,8 +144,8 @@ impl PyFrozenSet {
mod test {
use std::collections::{HashSet};
use super::{PySet, PyFrozenSet};
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use python::Python;
use conversion::{ToPyObject, PyTryFrom};
use objectprotocol::ObjectProtocol;
use instance::AsPyRef;
@ -165,11 +165,11 @@ mod test {
let mut v = HashSet::new();
let ob = v.to_object(py);
let set = PySet::downcast_from(ob.as_ref(py)).unwrap();
let set = PySet::try_from(ob.as_ref(py)).unwrap();
assert_eq!(0, set.len());
v.insert(7);
let ob = v.to_object(py);
let set2 = PySet::downcast_from(ob.as_ref(py)).unwrap();
let set2 = PySet::try_from(ob.as_ref(py)).unwrap();
assert_eq!(1, set2.len());
}

View file

@ -66,9 +66,9 @@ impl PyString {
/// even if the bytes are not valid UTF-8.
/// For unicode strings, returns the underlying representation used by Python.
pub fn data(&self) -> PyStringData {
if let Some(bytes) = self.cast_as::<PyBytes>() {
if let Ok(bytes) = self.cast_as::<PyBytes>() {
PyStringData::Utf8(bytes.data())
} else if let Some(unicode) = self.cast_as::<PyUnicode>() {
} else if let Ok(unicode) = self.cast_as::<PyUnicode>() {
unicode.data()
} else {
panic!("PyString is neither `str` nor `unicode`")
@ -175,7 +175,7 @@ impl PyUnicode {
impl std::convert::From<Py<PyBytes>> for Py<PyString> {
#[inline]
fn from(ob: Py<PyBytes>) -> Py<PyString> {
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
unsafe{std::mem::transmute(ob)}
}
}
@ -183,7 +183,7 @@ impl std::convert::From<Py<PyBytes>> for Py<PyString> {
impl std::convert::From<Py<PyUnicode>> for Py<PyString> {
#[inline]
fn from(ob: Py<PyUnicode>) -> Py<PyString> {
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
unsafe{std::mem::transmute(ob)}
}
}

View file

@ -2,11 +2,11 @@
use std::borrow::Cow;
use err::PyResult;
use python::Python;
use object::PyObject;
use objects::{PyObjectRef, PyString};
use objectprotocol::ObjectProtocol;
use python::{Python, PyDowncastFrom};
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject};
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject, PyTryFrom};
/// Converts Rust `str` to Python object.
/// See `PyString::new` for details on the conversion.
@ -59,14 +59,14 @@ impl<'source> ::FromPyObject<'source> for Cow<'source, str>
{
fn extract(ob: &'source PyObjectRef) -> PyResult<Self>
{
PyString::downcast_from(ob)?.to_string()
PyString::try_from(ob)?.to_string()
}
}
/// Allows extracting strings from Python objects.
/// Accepts Python `str` and `unicode` objects.
pyobject_extract!(py, obj to String => {
PyString::downcast_from(obj)?.to_string().map(Cow::into_owned)
PyString::try_from(obj)?.to_string().map(Cow::into_owned)
});
impl RefFromPyObject for str {

View file

@ -7,8 +7,8 @@ use err::{PyErr, PyResult};
use instance::{Py, PyObjectWithToken};
use object::PyObject;
use objects::PyObjectRef;
use python::{Python, ToPyPointer, IntoPyPointer, PyDowncastFrom};
use conversion::{FromPyObject, ToPyObject, IntoPyTuple, IntoPyObject};
use python::{Python, ToPyPointer, IntoPyPointer};
use conversion::{FromPyObject, ToPyObject, IntoPyTuple, IntoPyObject, PyTryFrom};
use super::exc;
/// Represents a Python `tuple` object.
@ -161,7 +161,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) {
fn extract(obj: &'s PyObjectRef) -> PyResult<Self>
{
let t = PyTuple::downcast_from(obj)?;
let t = PyTuple::try_from(obj)?;
let slice = t.as_slice();
if t.len() == $length {
Ok((
@ -238,7 +238,7 @@ impl IntoPyTuple for () {
/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
/// Otherwise, returns an error.
pyobject_extract!(py, obj to NoArgs => {
let t = PyTuple::downcast_from(obj)?;
let t = PyTuple::try_from(obj)?;
if t.len() == 0 {
Ok(NoArgs)
} else {
@ -251,8 +251,8 @@ pyobject_extract!(py, obj to NoArgs => {
mod test {
use PyTuple;
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use python::Python;
use conversion::{ToPyObject, PyTryFrom};
use objects::PyObjectRef;
use objectprotocol::ObjectProtocol;
@ -272,7 +272,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let ob = (1, 2, 3).to_object(py);
let tuple = PyTuple::downcast_from(ob.as_ref(py)).unwrap();
let tuple = PyTuple::try_from(ob.as_ref(py)).unwrap();
assert_eq!(3, tuple.len());
let ob: &PyObjectRef = tuple.into();
assert_eq!((1, 2, 3), ob.extract().unwrap());

View file

@ -13,6 +13,7 @@ use instance::{Py, PyToken, AsPyRef};
use object::PyObject;
use objects::{PyObjectRef, PyType, PyDict, PyModule};
use err::{PyErr, PyResult, PyDowncastError};
use conversion::PyTryFrom;
use pythonrun::{self, GILGuard};
@ -29,93 +30,10 @@ use pythonrun::{self, GILGuard};
#[derive(Copy, Clone)]
pub struct Python<'p>(PhantomData<&'p GILGuard>);
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PyDowncastFrom : Sized {
/// Cast from PyObject to a concrete Python object type.
fn try_downcast_from(&PyObjectRef) -> Option<&Self>;
/// Cast from PyObject to a concrete Python object type.
fn try_exact_downcast_from(ob: &PyObjectRef) -> Option<&Self> {
Self::try_downcast_from(ob)
}
/// Cast from PyObject to a concrete Python object type.
fn downcast_from(ob: &PyObjectRef) -> Result<&Self, PyDowncastError> {
if let Some(ob) = Self::try_downcast_from(ob) {
Ok(ob)
} else {
Err(PyDowncastError)
}
}
/// Cast from PyObject to a concrete Python object type.
fn exact_downcast_from(ob: &PyObjectRef) -> Result<&Self, PyDowncastError> {
if let Some(ob) = Self::try_exact_downcast_from(ob) {
Ok(ob)
} else {
Err(PyDowncastError)
}
}
/// Cast from PyObject to a concrete Python object type.
unsafe fn unchecked_downcast_from(&PyObjectRef) -> &Self;
/// Cast from PyObject to a concrete Python object type.
unsafe fn unchecked_mut_downcast_from(&PyObjectRef) -> &mut Self;
}
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PyMutDowncastFrom : Sized {
/// Cast from PyObject to a concrete Python object type.
fn try_mut_downcast_from(&mut PyObjectRef) -> Option<&mut Self>;
/// Cast from PyObject to a concrete Python object type.
fn try_mut_exact_downcast_from(ob: &mut PyObjectRef) -> Option<&mut Self> {
Self::try_mut_downcast_from(ob)
}
/// Cast from PyObject to a concrete Python object type.
fn mut_downcast_from(ob: &mut PyObjectRef) -> Result<&mut Self, PyDowncastError> {
if let Some(o) = Self::try_mut_downcast_from(ob) {
return Ok(o)
} else {
Err(PyDowncastError)
}
}
/// Cast from PyObject to a concrete Python object type.
fn mut_exact_downcast_from(ob: &mut PyObjectRef) -> Result<&mut Self, PyDowncastError> {
if let Some(ob) = Self::try_mut_exact_downcast_from(ob) {
Ok(ob)
} else {
Err(PyDowncastError)
}
}
}
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PyDowncastInto : Sized {
/// Cast Self to a concrete Python object type.
fn downcast_into<I>(Python, I) -> Result<Self, PyDowncastError>
where I: ToPyPointer + IntoPyPointer;
/// Cast from ffi::PyObject to a concrete Python object type.
fn downcast_into_from_ptr(py: Python, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError>;
/// Cast from ffi::PyObject to a concrete Python object type.
fn unchecked_downcast_into<I>(I) -> Self where I: IntoPyPointer;
}
/// This trait allows retrieving the underlying FFI pointer from Python objects.
pub trait ToPyPointer {
/// Retrieves the underlying FFI pointer (as a borrowed pointer).
fn as_ptr(&self) -> *mut ffi::PyObject;
}
/// This trait allows retrieving the underlying FFI pointer from Python objects.
@ -147,6 +65,15 @@ impl <T> IntoPyPointer for Option<T> where T: IntoPyPointer {
}
}
/// Gets the underlying FFI pointer, returns a borrowed pointer.
impl<'a, T> IntoPyPointer for &'a T where T: ToPyPointer {
#[inline]
default fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.as_ptr();
unsafe { ffi::Py_INCREF(ptr); }
ptr
}
}
impl<'p> Python<'p> {
/// Retrieve Python instance under the assumption that the GIL is already acquired at this point,
@ -217,7 +144,7 @@ impl<'p> Python<'p> {
}
let globals = globals.map(|g| g.as_ptr())
.unwrap_or_else(|| ffi::PyModule_GetDict(mptr));
.unwrap_or_else(|| ffi::PyModule_GetDict(mptr));
let locals = locals.map(|l| l.as_ptr()).unwrap_or(globals);
let res_ptr = ffi::PyRun_StringFlags(code.as_ptr(),
@ -280,9 +207,9 @@ impl<'p> Python<'p> {
/// Create new instance of `T` and move it under python management.
/// Created object get registered in release pool. Returns references to `T`
#[inline]
pub fn init_ref<T, F>(self, f: F) -> PyResult<&'p T>
pub fn init_ref<T, F>(self, f: F) -> PyResult<&'p T>
where F: FnOnce(PyToken) -> T,
T: PyTypeInfo + PyObjectAlloc<T> + PyDowncastFrom
T: PyTypeInfo + PyObjectAlloc<T>
{
Py::new_ref(self, f)
}
@ -292,7 +219,7 @@ impl<'p> Python<'p> {
#[inline]
pub fn init_mut<T, F>(self, f: F) -> PyResult<&'p mut T>
where F: FnOnce(PyToken) -> T,
T: PyTypeInfo + PyObjectAlloc<T> + PyDowncastFrom
T: PyTypeInfo + PyObjectAlloc<T>
{
Py::new_mut(self, f)
}
@ -300,22 +227,42 @@ impl<'p> Python<'p> {
impl<'p> Python<'p> {
unsafe fn unchecked_downcast<T: PyTypeInfo>(self, ob: &PyObjectRef) -> &'p T
{
if T::OFFSET == 0 {
&*(ob as *const _ as *const T)
} else {
let ptr = (ob.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T;
&*ptr
}
}
unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(self, ob: &PyObjectRef) -> &'p mut T
{
if T::OFFSET == 0 {
&mut *(ob as *const _ as *mut T)
} else {
let ptr = (ob.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T;
&mut *ptr
}
}
/// Register object in release pool, and try to downcast to specific type.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
where T: PyDowncastFrom
where T: PyTypeInfo
{
unsafe {
let p = pythonrun::register_owned(self, obj.into_ptr());
<T as PyDowncastFrom>::downcast_from(p)
T::try_from(p)
}
}
/// Register object in release pool, and do unchecked downcast to specific type.
pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'p T
where T: PyDowncastFrom
where T: PyTypeInfo
{
let p = pythonrun::register_owned(self, obj.into_ptr());
<T as PyDowncastFrom>::unchecked_downcast_from(p)
self.unchecked_downcast(p)
}
/// Register `ffi::PyObject` pointer in release pool
@ -331,26 +278,26 @@ impl<'p> Python<'p> {
/// Register `ffi::PyObject` pointer in release pool,
/// and do unchecked downcast to specific type.
pub unsafe fn cast_from_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p T
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
::err::panic_after_error();
} else {
let p = pythonrun::register_owned(self, ptr);
<T as PyDowncastFrom>::unchecked_downcast_from(p)
self.unchecked_downcast(p)
}
}
/// Register `ffi::PyObject` pointer in release pool,
/// Do unchecked downcast to specific type. Returns mutable reference.
pub unsafe fn mut_cast_from_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
::err::panic_after_error();
} else {
let p = pythonrun::register_owned(self, ptr);
<T as PyDowncastFrom>::unchecked_mut_downcast_from(p)
self.unchecked_mut_downcast(p)
}
}
@ -358,13 +305,13 @@ impl<'p> Python<'p> {
/// Returns `Err(PyErr)` if the pointer is `null`.
/// do unchecked downcast to specific type.
pub unsafe fn cast_from_ptr_or_err<T>(self, ptr: *mut ffi::PyObject) -> PyResult<&'p T>
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
Err(PyErr::fetch(self))
} else {
let p = pythonrun::register_owned(self, ptr);
Ok(<T as PyDowncastFrom>::unchecked_downcast_from(p))
Ok(self.unchecked_downcast(p))
}
}
@ -372,13 +319,13 @@ impl<'p> Python<'p> {
/// Returns `None` if the pointer is `null`.
/// do unchecked downcast to specific type.
pub unsafe fn cast_from_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject) -> Option<&'p T>
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
None
} else {
let p = pythonrun::register_owned(self, ptr);
Some(<T as PyDowncastFrom>::unchecked_downcast_from(p))
Some(self.unchecked_downcast(p))
}
}
@ -386,10 +333,10 @@ impl<'p> Python<'p> {
/// Panics if the pointer is `null`.
/// do unchecked downcast to specific type.
pub unsafe fn cast_from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p T
where T: PyDowncastFrom
where T: PyTypeInfo
{
let p = pythonrun::register_borrowed(self, ptr);
<T as PyDowncastFrom>::unchecked_downcast_from(p)
self.unchecked_downcast(p)
}
/// Register borrowed `ffi::PyObject` pointer in release pool.
@ -397,13 +344,13 @@ impl<'p> Python<'p> {
/// do unchecked downcast to specific type.
pub unsafe fn cast_from_borrowed_ptr_or_err<T>(self, ptr: *mut ffi::PyObject)
-> PyResult<&'p T>
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
Err(PyErr::fetch(self))
} else {
let p = pythonrun::register_borrowed(self, ptr);
Ok(<T as PyDowncastFrom>::unchecked_downcast_from(p))
Ok(self.unchecked_downcast(p))
}
}
@ -412,13 +359,13 @@ impl<'p> Python<'p> {
/// do unchecked downcast to specific `T`.
pub unsafe fn cast_from_borrowed_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject)
-> Option<&'p T>
where T: PyDowncastFrom
where T: PyTypeInfo
{
if ptr.is_null() {
None
} else {
let p = pythonrun::register_borrowed(self, ptr);
Some(<T as PyDowncastFrom>::unchecked_downcast_from(p))
Some(self.unchecked_downcast(p))
}
}
@ -426,10 +373,10 @@ impl<'p> Python<'p> {
/// Panics if the pointer is `null`.
/// do unchecked downcast to specific `T`, returns mutable reference.
pub unsafe fn mut_cast_from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
where T: PyDowncastFrom
where T: PyTypeInfo
{
let p = pythonrun::register_borrowed(self, ptr);
<T as PyDowncastFrom>::unchecked_mut_downcast_from(p)
self.unchecked_mut_downcast(p)
}
/// Release PyObject reference.

View file

@ -41,11 +41,21 @@ pub trait PyTypeInfo {
/// PyTypeObject instance for this type
unsafe fn type_object() -> &'static mut ffi::PyTypeObject;
/// Check `*mut ffi::PyObject` if it is the same type
fn is_instance(ptr: *mut ffi::PyObject) -> bool;
/// Check if `*mut ffi::PyObject` is instance of this type
fn is_instance(ptr: *mut ffi::PyObject) -> bool {
unsafe {ffi::PyObject_TypeCheck(ptr, Self::type_object()) != 0}
}
/// Check if `*mut ffi::PyObject` is exact instance of this type
fn is_exact_instance(ptr: *mut ffi::PyObject) -> bool {
unsafe {
(*ptr).ob_type == Self::type_object()
}
}
}
/// type object supports python GC
pub const PY_TYPE_FLAG_GC: usize = 1<<0;
@ -78,6 +88,11 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
<T as PyTypeInfo>::is_instance(ptr)
}
#[inline]
default fn is_exact_instance(ptr: *mut ffi::PyObject) -> bool {
<T as PyTypeInfo>::is_exact_instance(ptr)
}
}
/// A Python object allocator that is usable as a base type for #[class]
@ -100,6 +115,7 @@ impl<T> PyObjectAlloc<T> for T where T : PyTypeInfo {
T::init_type();
let obj = ffi::PyType_GenericAlloc(T::type_object(), 0);
println!("ALLOC {:?} {:?}", obj, ffi::Py_REFCNT(obj));
let ptr = (obj as *mut u8).offset(T::OFFSET) as *mut T;
std::ptr::write(ptr, value);

View file

@ -110,7 +110,7 @@ fn empty_class_with_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<EmptyClassWithNew>();
assert!(typeobj.call(NoArgs, None).unwrap().cast_as::<EmptyClassWithNew>().is_some());
assert!(typeobj.call(NoArgs, None).unwrap().cast_as::<EmptyClassWithNew>().is_ok());
}
#[py::class]

View file

@ -29,7 +29,7 @@ struct Test {
impl<'p> PyMappingProtocol<'p> for Test
{
fn __getitem__(&self, idx: &PyObjectRef) -> PyResult<PyObject> {
if let Some(slice) = idx.cast_as::<PySlice>() {
if let Ok(slice) = idx.cast_as::<PySlice>() {
let indices = slice.indices(1000)?;
if indices.start == 100 && indices.stop == 200 && indices.step == 1 {
return Ok("slice".into_object(self.py()))