Add PyDict and unchecked downcasts.

This commit is contained in:
Daniel Grunwald 2015-01-05 16:34:12 +01:00
parent eca5b4039b
commit c61e1e51f4
10 changed files with 307 additions and 68 deletions

View file

@ -1,8 +1,9 @@
use libc::c_char;
use std;
use ffi;
use err;
use {Python, PyObject, PyResult, PythonObject, PythonObjectDowncast, PyErr};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast};
use object::PyObject;
use err::{self, PyErr, PyResult};
use pyptr::{PyPtr, PythonPointer};
/// ToPyObject is implemented for types that can be converted into a python object.
@ -24,12 +25,14 @@ use pyptr::{PyPtr, PythonPointer};
/// m1(*try!(i.to_py_object(py)))
/// m2(i)
pub trait ToPyObject<'p, 's> for Sized? {
type ResultType : PythonObject<'p> = PyObject<'p>;
// The returned pointer type is flexible:
// it can be either &PyObject or PyPtr<PyObject>, depending on whether
// the conversion is allocating a new object.
// This lets us avoid a useless IncRef/DecRef pair
type PointerType : PythonPointer + std::ops::Deref //<Target = PyObject<'p>>
= PyPtr<'p, PyObject<'p>>;
type PointerType : PythonPointer + std::ops::Deref // <Target = Self::ResultType>
= PyPtr<'p, Self::ResultType>;
fn to_py_object(&'s self, py: Python<'p>) -> PyResult<'p, Self::PointerType>;
@ -59,6 +62,10 @@ pub trait ToPyObject<'p, 's> for Sized? {
// Note that the 'PointerType' associated type is essential to avoid unnecessarily
// touching the reference count in cases (2) and (4).
// Btw: I'm not sure if this type crazyness is worth it.
// If rust had automatic re-borrowing to avoid the '&*p' dance when using a PyPtr as &PyObject,
// we should probably just force the user to manually call .to_py()
}
/// FromPyObject is implemented by various types that can be extracted from a python object.
@ -72,15 +79,16 @@ pub trait FromPyObject<'p, 's> {
// convertible to a python object.
impl <'p, 's, T> ToPyObject<'p, 's> for T where T : PythonObject<'p> {
type PointerType = &'s PyObject<'p>;
type ResultType = T;
type PointerType = &'s T;
#[inline]
fn to_py_object(&'s self, py: Python<'p>) -> PyResult<'p, &'s PyObject<'p>> {
Ok(self.as_object())
fn to_py_object(&'s self, py: Python<'p>) -> PyResult<'p, &'s T> {
Ok(self)
}
}
impl <'p, 's, T> FromPyObject<'p, 's> for &'s T where T: PythonObjectDowncast<'p> {
impl <'p, 's, T> FromPyObject<'p, 's> for &'s T where T: PythonObjectWithCheckedDowncast<'p> {
#[inline]
fn from_py_object(s: &'s PyObject<'p>) -> PyResult<'p, &'s T> {
s.downcast()
@ -93,15 +101,16 @@ impl <'p, 's, T> FromPyObject<'p, 's> for &'s T where T: PythonObjectDowncast<'p
// convertible to a python object, without having to re-borrow the &PyObject.
impl <'p, 's, T> ToPyObject<'p, 's> for PyPtr<'p, T> where T: PythonObject<'p> {
type PointerType = &'s PyObject<'p>;
type ResultType = T;
type PointerType = &'s T;
#[inline]
fn to_py_object(&'s self, py: Python<'p>) -> PyResult<'p, &'s PyObject<'p>> {
Ok(self.as_object())
fn to_py_object(&'s self, py: Python<'p>) -> PyResult<'p, &'s T> {
Ok(&**self)
}
}
impl <'p, 's, T> FromPyObject<'p, 's> for PyPtr<'p, T> where T: PythonObjectDowncast<'p> {
impl <'p, 's, T> FromPyObject<'p, 's> for PyPtr<'p, T> where T: PythonObjectWithCheckedDowncast<'p> {
#[inline]
fn from_py_object(s : &'s PyObject<'p>) -> PyResult<'p, PyPtr<'p, T>> {
PyPtr::new(s).downcast_into()
@ -112,6 +121,7 @@ impl <'p, 's, T> FromPyObject<'p, 's> for PyPtr<'p, T> where T: PythonObjectDown
impl <'p, 's> ToPyObject<'p, 's> for bool {
type ResultType = PyObject<'p>;
type PointerType = &'p PyObject<'p>;
#[inline]
@ -137,6 +147,7 @@ impl <'p, 'a> FromPyObject<'p, 'a> for bool {
// When converting strings to/from python, we need to copy the string data.
// This means we can implement ToPyObject for str, but FromPyObject only for String.
impl <'p, 's> ToPyObject<'p, 's> for str {
type ResultType = PyObject<'p>;
type PointerType = PyPtr<'p, PyObject<'p>>;
fn to_py_object(&'s self, py : Python<'p>) -> PyResult<'p, PyPtr<'p, PyObject<'p>>> {

46
src/dict.rs Normal file
View file

@ -0,0 +1,46 @@
use std;
use ffi;
use python::{Python, PythonObject, PythonObjectDowncast};
use object::PyObject;
use typeobject::PyType;
use pyptr::PyPtr;
use err::{self, PyResult};
pub struct PyDict<'p>(PyObject<'p>);
impl <'p> PythonObject<'p> for PyDict<'p> {
#[inline]
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
&self.0
}
#[inline]
unsafe fn unchecked_downcast_from<'a>(obj: &'a PyObject<'p>) -> &'a PyDict<'p> {
std::mem::transmute(obj)
}
}
impl <'p> PythonObjectDowncast<'p> for PyDict<'p> {
#[inline]
fn downcast_from<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyDict<'p>> {
unsafe {
if ffi::PyDict_Check(obj.as_ptr()) {
Some(std::mem::transmute(obj))
} else {
None
}
}
}
#[inline]
fn type_object(py: Python<'p>, _ : Option<&Self>) -> &'p PyType<'p> {
unsafe { PyType::from_type_ptr(py, &mut ffi::PyDict_Type) }
}
}
impl <'p> PyDict<'p> {
fn new(py: Python<'p>) -> PyResult<'p, PyPtr<'p, PyDict<'p>>> {
unimplemented!()
}
}

View file

@ -1,15 +1,22 @@
use std;
use {PyObject, PythonObject, PyType, Python, PyPtr};
use pyptr::PythonPointer;
use {PyObject, PythonObject, PyType, Python};
use pyptr::{PyPtr, PythonPointer};
use ffi;
use libc;
use conversion::ToPyObject;
/// Represents a python exception that was raised.
#[derive(Clone, Show)]
pub struct PyErr<'p> {
ptype : Option<PyPtr<'p, PyObject<'p>>>,
pvalue : Option<PyPtr<'p, PyObject<'p>>>,
ptraceback : Option<PyPtr<'p, PyObject<'p>>>
/// Gets the type of the exception. This should be either a PyClass or a PyType.
pub ptype : PyPtr<'p, PyObject<'p>>,
/// Gets the value of the exception.
/// This can be either an instance of ptype,
/// a tuple of arguments to be passed to ptype's constructor,
/// or a single argument to be passed to ptype's constructor.
/// Call PyErr::instance() to get the exception instance in all cases.
pub pvalue : Option<PyPtr<'p, PyObject<'p>>>,
pub ptraceback : Option<PyPtr<'p, PyObject<'p>>> // is actually a PyTraceBack
}
@ -19,23 +26,106 @@ pub type PyPtrResult<'p, T> = PyResult<'p, PyPtr<'p, T>>;
impl <'p> PyErr<'p> {
/// Gets whether an error is present in the python interpreter's global state.
#[inline]
pub fn occurred(_ : Python<'p>) -> bool {
unsafe { !ffi::PyErr_Occurred().is_null() }
}
/// Retrieves the current error from the python interpreter's global state.
/// The error is cleared from the python interpreter.
/// If no error is set, returns a RuntimeError.
pub fn fetch(py : Python<'p>) -> PyErr<'p> {
unsafe {
let mut ptype : *mut ffi::PyObject = std::mem::uninitialized();
let mut pvalue : *mut ffi::PyObject = std::mem::uninitialized();
let mut ptraceback : *mut ffi::PyObject = std::mem::uninitialized();
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr {
ptype: PyPtr::from_owned_ptr_opt(py, ptype),
pvalue: PyPtr::from_owned_ptr_opt(py, pvalue),
ptraceback: PyPtr::from_owned_ptr_opt(py, pvalue)
}
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
}
}
unsafe fn new_from_ffi_tuple(py: Python<'p>, ptype: *mut ffi::PyObject, pvalue: *mut ffi::PyObject, ptraceback: *mut ffi::PyObject) -> PyErr<'p> {
// Note: must not panic to ensure all owned pointers get acquired correctly,
// and because we mustn't panic in normalize().
PyErr {
ptype: if ptype.is_null() {
unimplemented!()
} else {
PyPtr::from_owned_ptr(py, ptype)
},
pvalue: PyPtr::from_owned_ptr_opt(py, pvalue),
ptraceback: PyPtr::from_owned_ptr_opt(py, ptraceback)
}
}
/// Construct a new error.
/// `exc` is the exception type; usually one of the standard exceptions like `PyExc::runtime_error()`.
/// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor
pub fn new(exc: &PyObject<'p>, value: Option<PyPtr<'p, PyObject<'p>>>) -> PyErr<'p> {
PyErr {
ptype: PyPtr::new(exc),
pvalue: value,
ptraceback: None
}
}
/// Print a standard traceback to sys.stderr.
pub fn print(self) {
self.restore();
unsafe { ffi::PyErr_PrintEx(0) }
}
/// Print a standard traceback to sys.stderr.
pub fn print_and_set_sys_last_vars(self) {
self.restore();
unsafe { ffi::PyErr_PrintEx(1) }
}
/// Print a warning message to sys.stderr when an exception has been set but it is impossible for the interpreter to actually raise the exception.
/// It is used, for example, when an exception occurs in an __del__() method..
pub fn write_unraisable(self, context: &PyObject<'p>) {
self.restore();
unsafe { ffi::PyErr_WriteUnraisable(context.as_ptr()) }
}
/// Return true if the current exception matches the exception in `exc`.
/// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass.
/// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match.
pub fn matches(&self, exc: &PyObject) -> bool {
unsafe { ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc.as_ptr()) != 0 }
}
/// Normalizes the error. This ensures that the exception value is an instance of the exception type.
pub fn normalize(&mut self) {
// The normalization helper function involves temporarily moving out of the &mut self,
// which requires some unsafe trickery:
unsafe {
std::ptr::write(self, std::ptr::read(self).normalized());
}
// This is safe as long as normalized() doesn't unwind due to a panic.
}
/// Helper function for normalizing the error by deconstructing and reconstructing the PyErr.
/// Must not panic for safety in normalize()
fn normalized(self) -> PyErr<'p> {
let PyErr { ptype, pvalue, ptraceback } = self;
let py = ptype.python();
let mut ptype = ptype.steal_ptr();
let mut pvalue = pvalue.steal_ptr();
let mut ptraceback = ptraceback.steal_ptr();
unsafe {
ffi::PyErr_NormalizeException(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
}
}
/// Retrieves the exception instance for this error.
/// This method takes &mut self because the error might need to be normalized in order to create the exception instance.
pub fn instance(&mut self) -> &PyObject<'p> {
self.normalize();
match self.pvalue {
Some(ref instance) => &**instance,
None => self.ptype.python().None()
}
}
@ -46,18 +136,53 @@ impl <'p> PyErr<'p> {
ffi::PyErr_Restore(ptype.steal_ptr(), pvalue.steal_ptr(), ptraceback.steal_ptr())
}
}
#[allow(unused_variables)]
pub fn type_error(obj : &PyObject<'p>, expected_type : &PyType<'p>) -> PyErr<'p> {
let py = obj.python();
PyErr {
ptype: Some(unsafe { PyPtr::from_borrowed_ptr(py, ffi::PyExc_TypeError) }),
pvalue: None,
ptraceback: None
}
}
}
/// Contains getter functions for the python exception types.
#[allow(non_snake_case)]
pub mod exception_types {
macro_rules! exc_getter(
($name:ident) => (
#[inline]
pub fn $name(py: ::python::Python) -> &::object::PyObject {
unsafe { ::object::PyObject::from_ptr(py, ::ffi::$name) }
}
)
);
exc_getter!(PyExc_BaseException);
exc_getter!(PyExc_Exception);
exc_getter!(PyExc_StandardError);
exc_getter!(PyExc_LookupError);
exc_getter!(PyExc_AssertionError);
exc_getter!(PyExc_AttributeError);
exc_getter!(PyExc_EOFError);
exc_getter!(PyExc_EnvironmentError);
exc_getter!(PyExc_FloatingPointError);
exc_getter!(PyExc_IOError);
exc_getter!(PyExc_ImportError);
exc_getter!(PyExc_IndexError);
exc_getter!(PyExc_KeyError);
exc_getter!(PyExc_KeyboardInterrupt);
exc_getter!(PyExc_MemoryError);
exc_getter!(PyExc_NameError);
exc_getter!(PyExc_NotImplementedError);
exc_getter!(PyExc_OSError);
exc_getter!(PyExc_OverflowError);
exc_getter!(PyExc_ReferenceError);
exc_getter!(PyExc_RuntimeError);
exc_getter!(PyExc_SyntaxError);
exc_getter!(PyExc_SystemError);
exc_getter!(PyExc_SystemExit);
exc_getter!(PyExc_TypeError);
exc_getter!(PyExc_ValueError);
#[cfg(target_os="windows")]
exc_getter!(PyExc_WindowsError);
exc_getter!(PyExc_ZeroDivisionError);
}
/// Construct PyObject from the result of a python FFI call that returns a new reference (owned pointer).
/// Returns Err(PyErr) if the pointer is null.
/// Unsafe because the pointer might be invalid.
@ -98,8 +223,9 @@ mod tests {
fn set_typeerror() {
let gil = Python::acquire_gil();
let py = gil.python();
PyErr::type_error(py.None(), py.get_type::<PyType>()).restore();
PyErr::new(::err::exception_types::PyExc_TypeError(py), None).restore();
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py))
}
}

View file

@ -3,12 +3,14 @@
#![feature(associated_types)]
#![feature(globs)]
#![feature(slicing_syntax)]
#![feature(macro_rules)]
extern crate libc;
extern crate "python27-sys" as ffi;
pub use ffi::Py_ssize_t;
pub use err::{PyErr, PyResult};
pub use python::{Python, PythonObject, PythonObjectDowncast};
pub use err::exception_types::*;
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
pub use object::PyObject;
pub use typeobject::PyType;
pub use pyptr::PyPtr;

View file

@ -1,6 +1,6 @@
use std;
use ffi;
use python::{Python, PythonObject, PythonObjectDowncast};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
use object::PyObject;
use typeobject::PyType;
use pyptr::PyPtr;
@ -13,20 +13,27 @@ impl <'p> PythonObject<'p> for PyModule<'p> {
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
&self.0
}
#[inline]
unsafe fn unchecked_downcast_from<'a>(obj: &'a PyObject<'p>) -> &'a PyModule<'p> {
std::mem::transmute(obj)
}
}
impl <'p> PythonObjectDowncast<'p> for PyModule<'p> {
impl <'p> PythonObjectWithCheckedDowncast<'p> for PyModule<'p> {
#[inline]
fn from_object<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyModule<'p>> {
fn downcast_from<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyModule<'p>> {
unsafe {
if ffi::PyModule_Check(obj.as_ptr()) {
Some(std::mem::transmute(obj))
Some(PythonObject::unchecked_downcast_from(obj))
} else {
None
}
}
}
}
impl <'p> PythonObjectWithTypeObject<'p> for PyModule<'p> {
#[inline]
fn type_object(py: Python<'p>, _ : Option<&Self>) -> &'p PyType<'p> {
unsafe { PyType::from_type_ptr(py, &mut ffi::PyModule_Type) }

View file

@ -1,7 +1,7 @@
use std;
use libc;
use ffi;
use python::{Python, PythonObject, PythonObjectDowncast};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
use typeobject::PyType;
use err::{PyErr, PyResult};
@ -21,6 +21,11 @@ impl <'p> PythonObject<'p> for PyObject<'p> {
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
self
}
#[inline]
fn unchecked_downcast_from<'a>(o: &'a PyObject<'p>) -> &'a PyObject<'p> {
o
}
/// Retrieves the underlying FFI pointer associated with this python object.
#[inline]
@ -34,12 +39,14 @@ impl <'p> PythonObject<'p> for PyObject<'p> {
}
}
impl <'p> PythonObjectDowncast<'p> for PyObject<'p> {
impl <'p> PythonObjectWithCheckedDowncast<'p> for PyObject<'p> {
#[inline]
fn from_object<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyObject<'p>> {
fn downcast_from<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyObject<'p>> {
Some(obj)
}
}
impl <'p> PythonObjectWithTypeObject<'p> for PyObject<'p> {
#[inline]
fn type_object(py: Python<'p>, _ : Option<&Self>) -> &'p PyType<'p> {
unsafe { PyType::from_type_ptr(py, &mut ffi::PyBaseObject_Type) }
@ -73,11 +80,11 @@ impl <'p> PyObject<'p> {
/// Casts the PyObject to a concrete python object type.
/// Returns a python TypeError if the object is not of the expected type.
#[inline]
pub fn downcast<T : PythonObjectDowncast<'p>>(&self) -> PyResult<'p, &T> {
let obj_opt : Option<&T> = PythonObjectDowncast::from_object(self);
pub fn downcast<T : PythonObjectWithCheckedDowncast<'p>>(&self) -> PyResult<'p, &T> {
let obj_opt : Option<&T> = PythonObjectWithCheckedDowncast::downcast_from(self);
match obj_opt {
Some(obj) => Ok(obj),
None => Err(PyErr::type_error(self, PythonObjectDowncast::type_object(self.python(), obj_opt)))
None => Err(unimplemented!())
}
}
}

View file

@ -2,7 +2,7 @@ use std;
use std::cmp::Ordering;
use ffi;
use libc;
use python::{Python, PythonObject};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast};
use object::PyObject;
use pyptr::{PyPtr, PythonPointer, as_ptr};
use conversion::ToPyObject;
@ -204,16 +204,48 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> {
/// This is typically a new iterator but if the argument
/// is an iterator, this returns itself.
#[inline]
fn iter(&self) -> PyResult<'p, PyPtr<'p, PyObject<'p>>> {
unsafe {
fn iter(&self) -> PyResult<'p, PyPtr<'p, PyIterator<'p>>> {
let it = try!(unsafe {
result_from_owned_ptr(self.python(), ffi::PyObject_GetIter(self.as_ptr()))
}
});
it.downcast_into()
}
}
impl <'p> ObjectProtocol<'p> for PyObject<'p> {}
pub struct PyIterator<'p>(PyObject<'p>);
impl <'p> PythonObject<'p> for PyIterator<'p> {
#[inline]
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
&self.0
}
#[inline]
unsafe fn unchecked_downcast_from<'a>(o: &'a PyObject<'p>) -> &'a PyIterator<'p> {
std::mem::transmute(o)
}
}
impl <'p> PythonObjectWithCheckedDowncast<'p> for PyIterator<'p> {
#[inline]
fn downcast_from<'a>(o: &'a PyObject<'p>) -> Option<&'a PyIterator<'p>> {
unsafe {
if ffi::PyIter_Check(o.as_ptr()) {
Some(PythonObject::unchecked_downcast_from(o))
} else {
None
}
}
}
}
impl <'p> PyIterator<'p> {
/// Retrieves the next item from an iterator.
/// Returns None when the iterator is exhausted.
#[inline]
fn iter_next(&self) -> PyResult<'p, Option<PyPtr<'p, PyObject<'p>>>> {
pub fn iter_next(&self) -> PyResult<'p, Option<PyPtr<'p, PyObject<'p>>>> {
let py = self.python();
let r = unsafe { ffi::PyIter_Next(self.as_ptr()) };
if r.is_null() {
@ -228,6 +260,3 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> {
}
}
impl <'p> ObjectProtocol<'p> for PyObject<'p> {}

View file

@ -1,7 +1,7 @@
use std;
use std::ops::Deref;
use ffi;
use python::{Python, PythonObject, PythonObjectDowncast};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast};
use object::PyObject;
use err::{PyResult, PyErr};
//use conversion::{FromPyObject, ToPyObject};
@ -181,7 +181,7 @@ impl<'p> PyPtr<'p, PyObject<'p>> {
/// Casts the PyPtr<PyObject> to a PyPtr of a concrete python object type.
/// Returns a python TypeError if the object is not of the expected type.
#[inline]
pub fn downcast_into<T>(self) -> PyResult<'p, PyPtr<'p, T>> where T: PythonObjectDowncast<'p> {
pub fn downcast_into<T>(self) -> PyResult<'p, PyPtr<'p, T>> where T: PythonObjectWithCheckedDowncast<'p> {
// TODO: avoid unnecessary IncRef/DefRef
self.deref().downcast().map(PyPtr::new)
}

View file

@ -21,6 +21,10 @@ pub trait PythonObject<'p> : 'p {
/// Casts the python object to PyObject.
fn as_object(&self) -> &PyObject<'p>;
/// Unsafe downcast from &PyObject to &Self.
/// Undefined behavior if the input object does not have the expected type.
unsafe fn unchecked_downcast_from<'a>(&'a PyObject<'p>) -> &'a Self;
/// Retrieves the underlying FFI pointer associated with this python object.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
@ -35,14 +39,14 @@ pub trait PythonObject<'p> : 'p {
}
/// Trait implemented by python object types that allow a checked downcast.
pub trait PythonObjectDowncast<'p> : PythonObject<'p> {
// TODO: maybe add 'unsafe fn from_object_unchecked' to PythonObject/PythonObjectDowncast,
// and then implement from_object using type_object().is_instance() ?
pub trait PythonObjectWithCheckedDowncast<'p> : PythonObject<'p> {
/// Upcast from PyObject to a concrete python object type.
/// Returns None if the python object is not of the specified type.
fn from_object<'a>(&'a PyObject<'p>) -> Option<&'a Self>;
fn downcast_from<'a>(&'a PyObject<'p>) -> Option<&'a Self>;
}
/// Trait implemented by python object types that have a corresponding type object.
pub trait PythonObjectWithTypeObject<'p> : PythonObjectWithCheckedDowncast<'p> {
/// Retrieves the type object for this python object type.
/// Option<&Self> is necessary until UFCS is implemented.
fn type_object(Python<'p>, Option<&Self>) -> &'p PyType<'p>;
@ -99,9 +103,9 @@ impl<'p> Python<'p> {
/// Retrieves a reference to the type object for type T.
#[inline]
pub fn get_type<T>(self) -> &'p PyType<'p> where T: PythonObjectDowncast<'p> {
pub fn get_type<T>(self) -> &'p PyType<'p> where T: PythonObjectWithTypeObject<'p> {
let none : Option<&T> = None;
PythonObjectDowncast::type_object(self, none)
PythonObjectWithTypeObject::type_object(self, none)
}
}

View file

@ -1,4 +1,4 @@
use python::{Python, PythonObject, PythonObjectDowncast};
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
use object::PyObject;
use ffi;
use libc::c_char;
@ -20,25 +20,32 @@ impl <'p> PythonObject<'p> for PyType<'p> {
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
unsafe { std::mem::transmute(self) }
}
#[inline]
unsafe fn unchecked_downcast_from<'a>(obj: &'a PyObject<'p>) -> &'a PyType<'p> {
std::mem::transmute(obj)
}
#[inline]
fn python(&self) -> Python<'p> {
self.py
}
}
impl <'p> PythonObjectDowncast<'p> for PyType<'p> {
impl <'p> PythonObjectWithCheckedDowncast<'p> for PyType<'p> {
#[inline]
fn from_object<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyType<'p>> {
fn downcast_from<'a>(obj : &'a PyObject<'p>) -> Option<&'a PyType<'p>> {
unsafe {
if ffi::PyType_Check(obj.as_ptr()) {
Some(std::mem::transmute(obj))
Some(PythonObject::unchecked_downcast_from(obj))
} else {
None
}
}
}
}
impl <'p> PythonObjectWithTypeObject<'p> for PyType<'p> {
#[inline]
fn type_object(py: Python<'p>, _ : Option<&Self>) -> &'p PyType<'p> {
unsafe { PyType::from_type_ptr(py, &mut ffi::PyType_Type) }