Add PyBool and PyTuple impls

This commit is contained in:
Daniel Grunwald 2015-01-06 01:04:25 +01:00
parent 038dfc7474
commit 1c7eb2340d
6 changed files with 108 additions and 28 deletions

View File

@ -2,7 +2,7 @@ use libc::c_char;
use std;
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast};
use objects::PyObject;
use objects::{PyObject, PyBool};
use err::{self, PyErr, PyResult};
use pyptr::{PyPtr, PythonPointer};
@ -111,30 +111,25 @@ impl <'p, 's, T> FromPyObject<'p, 's> for PyPtr<'p, T> where T: PythonObjectWith
impl <'p> ToPyObject<'p> for bool {
type ObjectType = PyObject<'p>;
type ObjectType = PyBool<'p>;
#[inline]
fn to_py_object(self, py: Python<'p>) -> PyResult<'p, PyPtr<'p, PyObject<'p>>> {
Ok(PyPtr::new(if self { py.True() } else { py.False() }))
fn to_py_object(self, py: Python<'p>) -> PyResult<'p, PyPtr<'p, PyBool<'p>>> {
Ok(PyPtr::new(PyBool::get(py, self)))
}
#[inline]
fn with_py_object<F, R>(self, py: Python<'p>, f: F) -> PyResult<'p, R> where F: FnOnce(&PyObject) -> PyResult<'p, R> {
fn with_py_object<F, R>(self, py: Python<'p>, f: F) -> PyResult<'p, R>
where F: FnOnce(&PyBool) -> PyResult<'p, R>
{
// Avoid unnecessary Py_INCREF/Py_DECREF pair
f(if self { py.True() } else { py.False() })
f(PyBool::get(py, self))
}
}
impl <'p, 'a> FromPyObject<'p, 'a> for bool {
fn from_py_object(s: &'a PyObject<'p>) -> PyResult<'p, bool> {
let py = s.python();
if s == py.True() {
Ok(true)
} else if s == py.False() {
Ok(false)
} else {
unimplemented!()
}
Ok(try!(s.downcast::<PyBool>()).is_true())
}
}

View File

@ -82,16 +82,10 @@ impl <'p> PyErr<'p> {
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.
#[inline]
pub fn matches(&self, exc: &PyObject) -> bool {
unsafe { ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc.as_ptr()) != 0 }
}
@ -120,8 +114,22 @@ impl <'p> PyErr<'p> {
}
}
/// Retrieves the exception type.
/// If the exception type is an old-style class, returns oldstyle::PyClass.
pub fn get_type(&self) -> &PyType<'p> {
match self.ptype.downcast::<PyType>() {
Ok(t) => t,
Err(_) => unimplemented!()
/* match self.ptype.downcast::<PyClass>() {
Ok(_) => py.get_type::<PyClass>(),
Err(_) => py.get_type::<PyNone>()
}*/
}
}
/// 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.
/// 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 {

View File

@ -3,6 +3,10 @@ pub use self::typeobject::PyType;
pub use self::module::PyModule;
pub use self::string::{PyBytes, PyUnicode};
pub use self::iterator::PyIterator;
use python::{Python, PythonObject};
use pyptr::{PyPtr, PythonPointer};
use err::{PyErr, PyResult};
use ffi::{Py_ssize_t};
macro_rules! pythonobject_newtype_only_pythonobject(
($name: ident) => (
@ -55,7 +59,67 @@ mod string;
mod dict;
mod iterator;
pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);
pyobject_newtype!(PyList, PyList_Check, PyList_Type);
pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type);
impl <'p> PyBool<'p> {
#[inline]
pub fn get(py: Python<'p>, val: bool) -> &'p PyBool<'p> {
if val { py.True() } else { py.False() }
}
#[inline]
pub fn is_true(&self) -> bool {
self.as_ptr() == unsafe { ::ffi::Py_True() }
}
}
pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);
impl <'p> PyTuple<'p> {
pub fn new(py: Python<'p>, elements: &[&PyObject<'p>]) -> PyResult<'p, PyPtr<'p, PyTuple<'p>>> {
unsafe {
let len = elements.len();
let ptr = ::ffi::PyTuple_New(len as Py_ssize_t);
let t = try!(::err::result_from_owned_ptr(py, ptr)).unchecked_downcast_into::<PyTuple>();
for (i, e) in elements.iter().enumerate() {
::ffi::PyTuple_SET_ITEM(ptr, i as Py_ssize_t, e.steal_ptr());
}
Ok(t)
}
}
#[inline]
pub fn len(&self) -> uint {
// non-negative Py_ssize_t should always fit into Rust uint
unsafe {
::ffi::PyTuple_GET_SIZE(self.as_ptr()) as uint
}
}
#[inline]
pub fn as_slice<'a>(&'a self) -> &'a [&'a PyObject<'p>] {
// This is safe because &PyObject has the same memory layout as *mut ffi::PyObject,
// and because tuples are immutable.
unsafe {
let ptr = self.as_ptr() as *mut ::ffi::PyTupleObject;
::std::mem::transmute(::std::raw::Slice {
data: (*ptr).ob_item.as_ptr(),
len: self.len()
})
}
}
}
impl<'p> ::std::ops::Index<uint> for PyTuple<'p> {
type Output = PyObject<'p>;
#[inline]
fn index<'a>(&'a self, index: &uint) -> &'a PyObject<'p> {
// use as_slice() to use the normal Rust bounds checking when indexing
self.as_slice()[*index]
}
}

View File

@ -83,3 +83,11 @@ impl <'p> PyType<'p> {
}
}
impl <'p> PartialEq for PyType<'p> {
#[inline]
fn eq(&self, o : &PyType<'p>) -> bool {
self.as_type_ptr() == o.as_type_ptr()
}
}
impl <'p> Eq for PyType<'p> { }

View File

@ -176,5 +176,10 @@ impl<'p> PyPtr<'p, PyObject<'p>> {
// TODO: avoid unnecessary IncRef/DefRef
self.deref().downcast().map(PyPtr::new)
}
pub unsafe fn unchecked_downcast_into<T>(self) -> PyPtr<'p, T> where T: PythonObject<'p> {
// TODO: avoid unnecessary IncRef/DefRef
PyPtr::new(PythonObject::unchecked_downcast_from(self.deref()))
}
}

View File

@ -2,7 +2,7 @@ use std;
use std::kinds::marker::{NoSend, InvariantLifetime};
use std::ptr;
use ffi;
use objects::{PyObject, PyType};
use objects::{PyObject, PyType, PyBool};
use pythonrun::GILGuard;
/// The 'Python' struct is a zero-size marker struct that is required for most python operations.
@ -89,15 +89,15 @@ impl<'p> Python<'p> {
/// Retrieves a reference to the 'True' constant value.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
pub fn True(self) -> &'p PyObject<'p> {
unsafe { PyObject::from_ptr(self, ffi::Py_True()) }
pub fn True(self) -> &'p PyBool<'p> {
unsafe { PythonObject::unchecked_downcast_from(PyObject::from_ptr(self, ffi::Py_True())) }
}
/// Retrieves a reference to the 'False' constant value.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
pub fn False(self) -> &'p PyObject<'p> {
unsafe { PyObject::from_ptr(self, ffi::Py_False()) }
pub fn False(self) -> &'p PyBool<'p> {
unsafe { PythonObject::unchecked_downcast_from(PyObject::from_ptr(self, ffi::Py_False())) }
}
/// Retrieves a reference to the type object for type T.