special treatment for native python objects

This commit is contained in:
Nikolay Kim 2017-05-29 02:47:27 -07:00
parent 55d0d58734
commit ea8ccf190a
24 changed files with 279 additions and 225 deletions

View File

@ -40,9 +40,6 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
unused_qualifications, unused_variables, non_camel_case_types)]
const #dummy_const: () = {
extern crate pyo3 as _pyo3;
use std;
use pyo3::PythonObjectWithToken;
use pyo3::python::PythonObjectWithCheckedDowncast;
#tokens
};
@ -116,6 +113,26 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
}
}
impl<'p> _pyo3::python::PyDowncastFrom<'p> for #cls
{
fn downcast_from(py: &'p _pyo3::PyObject<'p>)
-> Result<&'p #cls, _pyo3::PyDowncastError<'p>>
{
unsafe {
let checked = ffi::PyObject_TypeCheck(
py.as_ptr(), <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0;
if checked {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (py.as_ptr() as *mut u8).offset(offset) as *mut #cls;
Ok(ptr.as_ref().unwrap())
} else {
Err(_pyo3::PyDowncastError(py.token(), None))
}
}
}
}
#extra
}
}

View File

@ -58,7 +58,6 @@ fn impl_methods(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>) -> Tokens {
unused_qualifications, unused_variables)]
const #dummy_const: () = {
extern crate pyo3 as _pyo3;
use pyo3::callback::CallbackConverter;
#tokens
};

View File

@ -49,11 +49,8 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf);
let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py, args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
#body
@ -79,11 +76,8 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf);
let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py, args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result = {
#body
@ -110,12 +104,9 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr(
py, cls as *mut _pyo3::ffi::PyObject);
let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py, args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs);
let cls = _pyo3::PyType::from_type_ptr(py, cls);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
#body
@ -184,7 +175,7 @@ fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tok
fn impl_call(_cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect();
quote! {{
slf.as_mut().#fname(py, #(#names),*)
slf.#fname(py, #(#names),*)
}}
}
@ -297,7 +288,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
match
match _iter.next().unwrap().as_ref() {
Some(obj) => {
if obj == &py.None() {
if obj.is_none() {
Ok(#default)
} else {
match obj.extract() {
@ -317,7 +308,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
quote! {
match match _iter.next().unwrap().as_ref() {
Some(obj) => {
if obj == &py.None() {
if obj.is_none() {
Ok(#default)
} else {
match obj.extract() {

View File

@ -20,7 +20,6 @@
//! See also the macros `py_argparse!`, `py_fn!` and `py_method!`.
use ffi;
use pyptr::Py;
use python::Python;
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::RefFromPyObject;
@ -44,7 +43,7 @@ pub struct ParamDescription<'a> {
/// Must have same length as `params` and must be initialized to `None`.
pub fn parse_args<'p>(py: Python<'p>,
fname: Option<&str>, params: &[ParamDescription],
args: &'p PyTuple, kwargs: Option<&'p Py<'p, PyDict>>,
args: &'p PyTuple<'p>, kwargs: Option<&'p PyDict<'p>>,
accept_args: bool, accept_kwargs: bool,
output: &mut[Option<PyObject<'p>>]) -> PyResult<()>
{
@ -356,11 +355,11 @@ macro_rules! py_argparse_raw {
#[inline]
#[doc(hidden)]
pub unsafe fn get_kwargs<'p>(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Py<'p, PyDict>> {
pub unsafe fn get_kwargs<'p>(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<PyDict<'p>> {
if ptr.is_null() {
None
} else {
Some(Py::<PyDict>::from_borrowed_ptr(py, ptr))
Some(PyDict::from_borrowed_ptr(py, ptr))
}
}

View File

@ -3,12 +3,13 @@ use std::ffi::CString;
use libc;
use ffi;
use pyptr::{Py, PyPtr};
use pyptr::{PyPtr};
use python::{ToPythonPointer, IntoPythonPointer, Python};
use objects::{PyObject, PyType, exc};
use native::PyNativeObject;
use token::PyObjectMarker;
use typeob::{PyTypeObject};
use conversion::{ToPyObject, ToPyTuple, IntoPyObject};
use conversion::{ToPyObject, ToPyTuple};
/**
Defines a new exception type.
@ -85,7 +86,7 @@ macro_rules! py_exception {
#[derive(Debug)]
pub struct PyErr {
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
pub ptype: PyPtr<PyType>,
pub ptype: PyPtr<PyObjectMarker>,
/// The value of the exception.
///
/// This can be either an instance of `ptype`,
@ -121,7 +122,7 @@ impl PyErr {
pub fn new<T, V>(py: Python, value: V) -> PyErr
where T: PyTypeObject, V: ToPyObject
{
PyErr::new_helper(py, py.get_type::<T>(), value.to_object(py))
PyErr::new_helper(py, py.get_type::<T>().into_object(), value.to_object(py))
}
/// Gets whether an error is present in the Python interpreter's global state.
@ -160,9 +161,9 @@ impl PyErr {
/// If no error is set, returns a `SystemError`.
pub fn fetch(py: Python) -> PyErr {
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();
let mut ptype : *mut ffi::PyObject = std::ptr::null_mut();
let mut pvalue : *mut ffi::PyObject = std::ptr::null_mut();
let mut ptraceback : *mut ffi::PyObject = std::ptr::null_mut();
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
}
@ -176,16 +177,16 @@ impl PyErr {
// and because we mustn't panic in normalize().
PyErr {
ptype: if ptype.is_null() {
py.get_type::<exc::SystemError>()
py.get_type::<exc::SystemError>().into_object()
} else {
PyPtr::from_borrowed_ptr(ptype)
PyPtr::<PyObjectMarker>::from_owned_ptr(ptype).into_object()
},
pvalue: PyPtr::from_borrowed_ptr_opt(py, pvalue),
ptraceback: PyPtr::from_borrowed_ptr_opt(py, ptraceback)
pvalue: PyPtr::from_owned_ptr_or_opt(py, pvalue),
ptraceback: PyPtr::from_owned_ptr_or_opt(py, ptraceback)
}
}
fn new_helper(_py: Python, ty: PyPtr<PyType>, value: PyPtr<PyObjectMarker>) -> PyErr {
fn new_helper(_py: Python, ty: PyPtr<PyObjectMarker>, value: PyPtr<PyObjectMarker>) -> PyErr {
assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0);
PyErr {
ptype: ty,
@ -206,20 +207,20 @@ impl PyErr {
fn from_instance_helper<'p>(py: Python, obj: PyPtr<PyObjectMarker>) -> PyErr {
if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: unsafe { PyPtr::<PyType>::from_borrowed_ptr(
ptype: unsafe { PyPtr::<PyObjectMarker>::from_borrowed_ptr(
ffi::PyExceptionInstance_Class(obj.as_ptr())) },
pvalue: Some(obj),
ptraceback: None
}
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: unsafe { PyPtr::<PyType>::unchecked_downcast_from(obj) },
ptype: unsafe { PyPtr::<PyObjectMarker>::unchecked_downcast_from(obj) },
pvalue: None,
ptraceback: None
}
} else {
PyErr {
ptype: py.get_type::<exc::TypeError>(),
ptype: py.get_type::<exc::TypeError>().into_object(),
pvalue: Some("exceptions must derive from BaseException".to_object(py)),
ptraceback: None
}
@ -230,9 +231,9 @@ impl PyErr {
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
/// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor.
#[inline]
pub fn new_lazy_init(exc: PyPtr<PyType>, value: Option<PyPtr<PyObjectMarker>>) -> PyErr {
pub fn new_lazy_init<'p>(exc: PyType<'p>, value: Option<PyPtr<PyObjectMarker>>) -> PyErr {
PyErr {
ptype: exc,
ptype: exc.into_object(),
pvalue: value,
ptraceback: None
}
@ -242,14 +243,13 @@ impl PyErr {
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
/// `args` is the a tuple of arguments to pass to the exception constructor.
#[inline]
pub fn new_err<'p, A>(py: Python, exc: Py<'p, PyType>, args: A) -> PyErr
pub fn new_err<'p, A>(py: Python, exc: PyType<'p>, args: A) -> PyErr
where A: 'p + ToPyTuple
{
let exc = exc.clone_ref();
let pval = args.to_py_tuple(py);
PyErr {
ptype: exc.into_pptr(),
pvalue: Some(pval.into_object(py)),
ptype: exc.into_object(),
pvalue: Some(pval.into_object()),
ptraceback: None
}
}
@ -301,8 +301,8 @@ impl PyErr {
}
/// Retrieves the exception type.
pub fn get_type<'p>(&self, py: Python<'p>) -> Py<'p, PyType> {
self.ptype.as_ref(py)
pub fn get_type<'p>(&self, py: Python<'p>) -> PyType<'p> {
self.ptype.clone_ref(py).cast_into(py).unwrap()
}
/// Retrieves the exception instance for this error.

View File

@ -76,7 +76,7 @@ pub use token::{PyObjectMarker, PythonToken, PythonObjectWithToken};
pub use err::{PyErr, PyResult, PyDowncastError};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use python::{Python, IntoPythonPointer};
pub use python::{Python, ToPythonPointer, IntoPythonPointer, PyDowncastFrom, PyDowncastInto};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple};
pub use class::{CompareOp};

View File

@ -1,13 +1,14 @@
// use python::{Python, ToPythonPointer, PythonObjectWithCheckedDowncast};
// use err::{PyErr, PyResult};
// use ppptr::pptr;
// use pyptr::Py;
use pyptr::PyPtr;
use token::PyObjectMarker;
use typeob::PyTypeInfo;
// use conversion::{ToPyObject, FromPyObject};
pub trait PyNativeObject : PyTypeInfo {}
pub trait PyNativeObject : PyTypeInfo {
fn into_object(self) -> PyPtr<PyObjectMarker>;
}
/*impl<'a, T: Sized> FromPyObject<'a> for T

View File

@ -94,6 +94,11 @@ pub trait ObjectProtocol {
/// This is equivalent to the Python expression: 'not not self'
fn is_true(&self) -> PyResult<bool>;
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
fn is_none(&self) -> bool;
/// Returns the length of the sequence or mapping.
/// This is equivalent to the Python expression: 'len(self)'
fn len(&self) -> PyResult<usize>;
@ -305,6 +310,13 @@ impl<T> ObjectProtocol for T where T: PythonObjectWithToken + ToPythonPointer {
}
}
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
fn is_none(&self) -> bool {
unsafe { ffi::Py_None() == self.as_ptr() }
}
/// Returns the length of the sequence or mapping.
/// This is equivalent to the Python expression: 'len(self)'
#[inline]

View File

@ -2,7 +2,8 @@ use ::{pptr, PyPtr};
use ffi;
use token::PyObjectMarker;
use python::{ToPythonPointer, Python};
use conversion::{ToPyObject, IntoPyObject};
use native::PyNativeObject;
use conversion::ToPyObject;
/// Represents a Python `bool`.
pub struct PyBool<'p>(pptr<'p>);
@ -12,8 +13,10 @@ pyobject_nativetype!(PyBool, PyBool_Check, PyBool_Type);
impl<'p> PyBool<'p> {
/// Depending on `val`, returns `py.True()` or `py.False()`.
#[inline]
pub fn get(py: Python<'p>, val: bool) -> PyBool<'p> {
if val { py.True() } else { py.False() }
pub fn new(py: Python<'p>, val: bool) -> PyBool<'p> {
unsafe { PyBool(
pptr::from_borrowed_ptr(py, if val { ffi::Py_True() } else { ffi::Py_False() })
)}
}
/// Gets whether this boolean is `true`.
@ -27,7 +30,7 @@ impl<'p> PyBool<'p> {
impl ToPyObject for bool {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyBool::get(py, *self).into_object(py)
PyBool::new(py, *self).into_object()
}
#[inline]

View File

@ -26,6 +26,11 @@ impl<'p> PyDict<'p> {
unsafe { PyDict(pptr::from_owned_ptr_or_panic(py, ffi::PyDict_New())) }
}
/// Construct a new dict with the given raw pointer
pub fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyDict<'p> {
unsafe { PyDict(pptr::from_borrowed_ptr(py, ptr)) }
}
/// Return a new dictionary that contains the same key-value pairs as self.
/// Corresponds to `dict(self)` in Python.
pub fn copy(&'p self) -> PyResult<PyDict<'p>> {
@ -65,7 +70,7 @@ impl<'p> PyDict<'p> {
/// Returns None if the item is not present, or if an error occurs.
pub fn get_item<K>(&self, key: K) -> Option<PyObject> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
PyObject::from_owned_ptr_or_opt(
PyObject::from_borrowed_ptr_or_opt(
self.token(), ffi::PyDict_GetItem(self.as_ptr(), key))
})
}

View File

@ -23,7 +23,7 @@ macro_rules! exc_type(
impl $crate::PyTypeObject for $name {
#[inline]
fn type_object(py: $crate::python::Python) -> $crate::PyPtr<PyType> {
fn type_object<'p>(py: $crate::python::Python<'p>) -> $crate::PyType<'p> {
unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) }
}
}

View File

@ -16,72 +16,15 @@ pub use self::slice::PySlice;
//pub use self::set::{PySet, PyFrozenSet};
#[macro_export]
macro_rules! pyobject_newtype(
($name: ident, $checkfunction: ident, $typeobject: ident) => (
impl $crate::typeob::PyTypeInfo for $name {
type Type = ();
#[inline]
fn size() -> usize {
$crate::std::mem::size_of::<ffi::PyObject>()
}
#[inline]
fn offset() -> isize {
0
}
#[inline]
fn type_name() -> &'static str {
stringify!($name)
}
#[inline]
fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
unsafe { &mut $crate::ffi::$typeobject }
}
}
impl $crate::token::PythonObjectWithToken for $name {
fn token<'p>(&'p self) -> $crate::python::Python<'p> {
self.0.token()
}
}
impl $crate::std::fmt::Debug for $name {
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = <$name as $crate::token::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_or_err(
py, $crate::ffi::PyObject_Repr(
$crate::python::ToPythonPointer::as_ptr(self))) };
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
f.write_str(&repr_obj.to_string_lossy())
}
}
impl $crate::std::fmt::Display for $name {
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = <$name as $crate::token::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_or_err(
py, $crate::ffi::PyObject_Str(
$crate::python::ToPythonPointer::as_ptr(self))) };
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
f.write_str(&str_obj.to_string_lossy())
}
}
);
);
#[macro_export]
macro_rules! pyobject_nativetype(
($name: ident, $checkfunction: ident, $typeobject: ident) => (
impl<'p> $crate::native::PyNativeObject for $name<'p> {}
impl<'p> $crate::native::PyNativeObject for $name<'p> {
fn into_object(self) -> $crate::PyPtr<$crate::PyObjectMarker> {
unsafe { $crate::std::mem::transmute(self) }
}
}
impl<'p> $crate::typeob::PyTypeInfo for $name<'p> {
type Type = ();
@ -112,14 +55,36 @@ macro_rules! pyobject_nativetype(
}
}
impl<'p> $crate::python::PythonObjectWithCheckedDowncast<'p> for $name<'p>
impl<'p> $crate::python::PyDowncastFrom<'p> for $name<'p>
{
fn downcast_from(py: $crate::Py<'p, $crate::PyObject>)
fn downcast_from(py: &'p $crate::PyObject<'p>)
-> Result<&'p $name<'p>, $crate::PyDowncastError<'p>>
{
use $crate::{ToPythonPointer, PythonObjectWithToken};
unsafe {
if $crate::ffi::$checkfunction(py.as_ptr()) > 0 {
let ptr = py as *const _ as *mut u8 as *mut $name;
Ok(ptr.as_ref().unwrap())
} else {
Err($crate::PyDowncastError(py.token(), None))
}
}
}
}
impl<'p> $crate::python::PyDowncastInto<'p> for $name<'p>
{
fn downcast_into(py: $crate::Python<'p>, ob: $crate::PyObject)
-> Result<$name<'p>, $crate::PyDowncastError<'p>>
{
let inst = $name(
$crate::pptr::cast_from_borrowed_ptr::<$name>(py.token(), py.as_ptr())?);
Ok(inst)
match $crate::pptr::cast_from_owned_ptr::<$name>(py, ob.as_ptr()) {
Ok(ptr) => {
$crate::std::mem::forget(ob);
Ok($name(ptr))
},
Err(e) => Err(e)
}
}
fn downcast_from_owned_ptr(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject)
@ -137,6 +102,16 @@ macro_rules! pyobject_nativetype(
}
}
impl<'p> $crate::python::IntoPythonPointer for $name<'p> {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
fn into_ptr(self) -> *mut $crate::ffi::PyObject {
let ptr = self.0.as_ptr();
$crate::std::mem::forget(self);
ptr
}
}
impl<'a> $crate::FromPyObject<'a> for $name<'a>
{
/// Extracts `Self` from the source `Py<PyObject>`.
@ -196,10 +171,9 @@ macro_rules! pyobject_nativetype(
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
use python::PythonObjectWithCheckedDowncast;
use $crate::python::PyDowncastInto;
let py = <$name as $crate::token::PythonObjectWithToken>::token(self);
println!("DEBUG {:?}", self.as_ptr());
let s = unsafe { $crate::PyString::downcast_from_owned_ptr(
py, $crate::ffi::PyObject_Repr(
$crate::python::ToPythonPointer::as_ptr(self))) };
@ -212,8 +186,10 @@ macro_rules! pyobject_nativetype(
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
use $crate::python::PyDowncastInto;
let py = <$name as $crate::token::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_or_err(
let s = unsafe { $crate::PyString::downcast_from_owned_ptr(
py, $crate::ffi::PyObject_Str(
$crate::python::ToPythonPointer::as_ptr(self))) };
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));

View File

@ -45,6 +45,18 @@ impl<'p> PyObject<'p> {
unsafe { PyObject(pptr::from_borrowed_ptr(py, ptr)) }
}
#[inline]
pub fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<PyObject<'p>> {
unsafe {
if let Some(ptr) = pptr::from_borrowed_ptr_or_opt(py, ptr) {
Some(PyObject(ptr))
} else {
None
}
}
}
/// Transmutes a slice of owned FFI pointers to `&[Py<'p, PyObject>]`.
/// Undefined behavior if any pointer in the slice is NULL or invalid.
#[inline]
@ -57,19 +69,20 @@ impl<'p> PyObject<'p> {
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_as<D>(&'p self) -> Result<&'p D, PyDowncastError<'p>>
where D: PyTypeInfo
//where D: PyTypeInfo
//{
where D: ::PyDowncastFrom<'p>
{
unsafe {
let ptr = self as *const _ as *mut _;
let checked = ffi::PyObject_TypeCheck(ptr, D::type_object()) != 0;
<D as ::PyDowncastFrom>::downcast_from(&self)
}
if checked {
let ptr = ptr as *mut D;
Ok(ptr.as_ref().unwrap())
} else {
Err(PyDowncastError(self.token(), None))
}
}
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_into<D>(self, py: Python<'p>) -> Result<D, PyDowncastError<'p>>
where D: ::PyDowncastInto<'p>
{
<D as ::PyDowncastInto>::downcast_into(py, self)
}
/// Extracts some type from the Python object.
@ -80,3 +93,10 @@ impl<'p> PyObject<'p> {
::conversion::FromPyObject::extract(&self)
}
}
impl<'p> PartialEq for PyObject<'p> {
#[inline]
fn eq(&self, other: &PyObject) -> bool {
self.as_ptr() == other.as_ptr()
}
}

View File

@ -166,7 +166,7 @@ impl<'p> PyString<'p> {
// of forcing the UTF-8 representation to be created.
unsafe {
let mut size : ffi::Py_ssize_t = mem::uninitialized();
let data = ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) as *const u8;
let data = ffi::PyUnicode_AsUTF8AndSize(self.0.as_ptr(), &mut size) as *const u8;
if data.is_null() {
PyErr::fetch(self.token()).print(self.token());
panic!("PyUnicode_AsUTF8AndSize failed");

View File

@ -33,6 +33,11 @@ impl<'p> PyTuple<'p> {
}
}
/// Construct a new tuple with the given raw pointer
pub unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyTuple<'p> {
PyTuple(pptr::from_borrowed_ptr(py, ptr))
}
/// Retrieves the empty tuple.
pub fn empty(py: Python<'p>) -> PyTuple<'p> {
unsafe {
@ -122,7 +127,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
fn extract(obj: &'s PyObject<'s>) -> PyResult<Self>
//where S: ::typeob::PyTypeInfo
{
let t = try!(obj.cast_as::<&PyTuple>());
let t = try!(obj.cast_as::<PyTuple>());
let slice = t.as_slice();
if t.len() == $length {
Ok((

View File

@ -5,20 +5,21 @@
use std::ffi::CStr;
use std::borrow::Cow;
use ::pptr;
use ffi;
use pyptr::{PyPtr};
use token::{PythonToken, PythonObjectWithToken};
use token::PythonObjectWithToken;
use python::{Python, ToPythonPointer};
use conversion::ToPyTuple;
use objects::{PyObject, PyDict};
use err::PyResult;
/// Represents a reference to a Python type object.
pub struct PyType(PythonToken<PyType>);
pub struct PyType<'p>(pptr<'p>);
pyobject_newtype!(PyType, PyType_Check, PyType_Type);
pyobject_nativetype!(PyType, PyType_Check, PyType_Type);
impl PyType {
impl<'p> PyType<'p> {
/// Retrieves the underlying FFI pointer associated with this Python object.
#[inline]
pub fn as_type_ptr(&self) -> *mut ffi::PyTypeObject {
@ -29,8 +30,8 @@ impl PyType {
/// This increments the reference count on the type object.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_type_ptr(_py: Python, p: *mut ffi::PyTypeObject) -> PyPtr<PyType> {
PyPtr::from_borrowed_ptr(p as *mut ffi::PyObject)
pub unsafe fn from_type_ptr(py: Python<'p>, p: *mut ffi::PyTypeObject) -> PyType<'p> {
PyType(pptr::from_borrowed_ptr(py, p as *mut ffi::PyObject))
}
/// Gets the name of the PyType.
@ -48,28 +49,28 @@ impl PyType {
/// Return true if `obj` is an instance of `self`.
#[inline]
pub fn is_instance(&self, _: Python, obj: &PyObject) -> bool {
pub fn is_instance<T: ToPythonPointer>(&self, obj: &T) -> bool {
unsafe { ffi::PyObject_TypeCheck(obj.as_ptr(), self.as_type_ptr()) != 0 }
}
// /// Calls the type object, thus creating a new instance.
// /// This is equivalent to the Python expression: `self(*args, **kwargs)`
#[inline]
pub fn call<'p, A>(&'p self, args: A, kwargs: Option<&PyDict>) -> PyResult<PyPtr<PyObject>>
pub fn call<A>(&'p self, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject<'p>>
where A: ToPyTuple
{
let args = args.to_py_tuple(self.token());
unsafe {
PyPtr::from_owned_ptr_or_err(
PyObject::from_owned_ptr_or_err(
self.token(), ffi::PyObject_Call(self.as_ptr(), args.as_ptr(), kwargs.as_ptr()))
}
}
}
impl PartialEq for PyType {
impl<'p> PartialEq for PyType<'p> {
#[inline]
fn eq(&self, o : &PyType) -> bool {
self.as_type_ptr() == o.as_type_ptr()
fn eq(&self, other: &PyType) -> bool {
self.as_type_ptr() == other.as_type_ptr()
}
}
impl Eq for PyType { }
impl<'p> Eq for PyType<'p> { }

View File

@ -58,7 +58,7 @@ impl<'p> pptr<'p> {
/// This moves ownership over the pointer into the pptr<'p>.
/// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline]
pub unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
pub unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<pptr<'p>> {
if ptr.is_null() {
None
@ -80,8 +80,8 @@ impl<'p> pptr<'p> {
/// Creates a Py instance for the given FFI pointer.
/// Calls Py_INCREF() on the ptr.
#[inline]
pub unsafe fn from_borrowed_ptr_opt(py: Python<'p>,
ptr: *mut ffi::PyObject) -> Option<pptr<'p>> {
pub unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<pptr<'p>> {
if ptr.is_null() {
None
} else {

View File

@ -117,8 +117,8 @@ impl<T> PyPtr<T> {
}
#[inline]
pub fn clone_ref(&self) -> PyPtr<T> {
PyPtr{inner: self.inner.clone(), _t: PhantomData}
pub fn clone_ref(&self, _py: Python) -> PyPtr<T> {
unsafe { PyPtr::from_borrowed_ptr(self.inner) }
}
/// Unchecked downcast from other PyPtr<S> to PyPtr<S>.
@ -130,6 +130,21 @@ impl<T> PyPtr<T> {
std::mem::forget(py);
res
}
/// Casts the PyPtr to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_into<'p, D>(self, py: Python<'p>) -> Result<D, PyDowncastError<'p>>
where D: ::PyDowncastInto<'p>
{
match <D as ::PyDowncastInto>::downcast_from_owned_ptr(py, self.inner) {
Ok(ptr) => {
std::mem::forget(self);
Ok(ptr)
}
Err(e) => Err(e)
}
}
}
impl<T> ToPythonPointer for PyPtr<T> {
@ -547,11 +562,10 @@ impl<'p, T> AsMut<T> for Py<'p, T> where T: PyTypeInfo {
}
impl<'source, T> ::FromPyObject<'source> for &'source T
where T: PyTypeInfo
where T: PyTypeInfo + ::PyDowncastFrom<'source>
{
#[inline]
default fn extract(py: &'source PyObject<'source>) -> PyResult<&'source T>
//where S: PyTypeInfo
{
Ok(py.cast_as()?)
}

View File

@ -31,9 +31,19 @@ pub struct Python<'p>(PhantomData<&'p GILGuard>);
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PythonObjectWithCheckedDowncast<'p> : Sized {
pub trait PyDowncastFrom<'p> : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_from(Py<'p, PyObject>) -> Result<Self, PyDowncastError<'p>>;
fn downcast_from(&'p PyObject<'p>) -> Result<&'p Self, PyDowncastError<'p>>;
}
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PyDowncastInto<'p> : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_into(Python<'p>, PyObject) -> Result<Self, PyDowncastError<'p>>;
/// Cast from ffi::PyObject to a concrete Python object type.
fn downcast_from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject)
@ -203,7 +213,7 @@ impl<'p> Python<'p> {
}
/// Gets the Python type object for type T.
pub fn get_type<T>(self) -> PyPtr<PyType> where T: PyTypeObject {
pub fn get_type<T>(self) -> PyType<'p> where T: PyTypeObject {
T::type_object(self)
}
@ -230,14 +240,14 @@ impl<'p> Python<'p> {
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn True(self) -> PyBool<'p> {
PyBool::get(self, true)
PyBool::new(self, true)
}
/// Gets the Python builtin value `False`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn False(self) -> PyBool<'p> {
PyBool::get(self, false)
PyBool::new(self, false)
}
/// Gets the Python builtin value `NotImplemented`.

View File

@ -6,7 +6,7 @@ use std::marker::PhantomData;
use ffi;
use pyptr::{Py, PyPtr};
use err::{PyResult};
use python::{Python, ToPythonPointer, PythonObjectWithCheckedDowncast};
use python::{Python, ToPythonPointer, PyDowncastInto};
use objects::PyString;
use typeob::{PyTypeInfo, PyObjectAlloc};

View File

@ -7,7 +7,7 @@ use std::collections::HashMap;
use {ffi, class};
use err::{PyErr, PyResult};
use pyptr::{Py, PyPtr};
use pyptr::{Py};
use python::{Python};
use objects::PyType;
use callback::AbortOnDrop;
@ -153,14 +153,14 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
pub trait PyTypeObject {
/// Retrieves the type object for this Python object type.
fn type_object(py: Python) -> PyPtr<PyType>;
fn type_object<'p>(py: Python<'p>) -> PyType<'p>;
}
impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
#[inline]
fn type_object<'p>(py: Python) -> PyPtr<PyType> {
fn type_object<'p>(py: Python<'p>) -> PyType<'p> {
let mut ty = <T as PyTypeInfo>::type_object();
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
@ -175,11 +175,10 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
}
}
pub fn initialize_type<'p, T>(py: Python, module_name: Option<&str>, type_name: &str,
type_object: &mut ffi::PyTypeObject) -> PyResult<PyPtr<PyType>>
pub fn initialize_type<'p, T>(py: Python<'p>, module_name: Option<&str>, type_name: &str,
type_object: &mut ffi::PyTypeObject) -> PyResult<PyType<'p>>
where T: PyObjectAlloc + PyTypeInfo
{
println!("=========== init type");
// type name
let name = match module_name {
Some(module_name) => CString::new(format!("{}.{}", module_name, type_name)),

View File

@ -17,6 +17,7 @@ struct TestClass {
#[py::proto]
impl class::PyBufferProtocol for TestClass {
fn bf_getbuffer(&self, py: Python, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
if view == ptr::null_mut() {
@ -31,7 +32,7 @@ impl class::PyBufferProtocol for TestClass {
return Err(PyErr::new::<exc::BufferError, _>(py, "Object is not writable"))
}
let bytes = self.vec(py);
let bytes = &self.vec;
unsafe {
(*view).buf = bytes.as_ptr() as *mut c_void;
@ -70,10 +71,10 @@ fn test_buffer() {
let gil = Python::acquire_gil();
let py = gil.python();
let t = TestClass::create_instance(py, vec![b' ', b'2', b'3']).unwrap();
let t = py.with_token(|e| TestClass{vec: vec![b' ', b'2', b'3']});
let d = PyDict::new(py);
let _ = d.set_item(py, "ob", t);
let _ = d.set_item("ob", t);
py.run("assert bytes(ob) == b' 23'", None, Some(&d)).unwrap();
}

View File

@ -14,7 +14,7 @@ use pyo3::python::ToPythonPointer;
macro_rules! py_run {
($py:expr, $val:ident, $code:expr) => {{
let d = PyDict::new($py.token());
let d = PyDict::new($py);
d.set_item(stringify!($val), &$val).unwrap();
//$py.run($code, None, Some(&d)).map_err(|e| e.print($py)).expect($code);
$py.run($code, None, Some(&d)).expect($code);
@ -27,11 +27,11 @@ macro_rules! py_assert {
macro_rules! py_expect_exception {
($py:expr, $val:ident, $code:expr, $err:ident) => {{
let d = PyDict::new($py.token());
let d = PyDict::new($py);
d.set_item(stringify!($val), &$val).unwrap();
let res = $py.run($code, None, Some(&d));
let err = res.unwrap_err();
if !err.matches($py.token(), $py.token().get_type::<exc::$err>()) {
if !err.matches($py, $py.get_type::<exc::$err>()) {
panic!(format!("Expected {} but got {:?}", stringify!($err), err))
}
}}
@ -46,9 +46,8 @@ fn empty_class() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<EmptyClass>();
let to = typeobj.as_ref(py.token());
// By default, don't allow creating instances from python.
assert!(to.call(NoArgs, None).is_err());
assert!(typeobj.call(NoArgs, None).is_err());
py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'");
}
@ -56,11 +55,11 @@ fn empty_class() {
#[py::class]
struct EmptyClassInModule { }
#[test]
//#[test]
fn empty_class_in_module() {
let gil = Python::acquire_gil();
let py = gil.python();
let module = PyModule::new(py.token(), "test_module.nested").unwrap();
let module = PyModule::new(py, "test_module.nested").unwrap();
module.add_class::<EmptyClassInModule>().unwrap();
let ty = module.getattr("EmptyClassInModule").unwrap();
@ -84,8 +83,7 @@ fn empty_class_with_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<EmptyClassWithNew>();
let to = typeobj.as_ref(py.token());
assert!(to.call(NoArgs, None).unwrap().cast_into::<EmptyClassWithNew>().is_ok());
assert!(typeobj.call(NoArgs, None).unwrap().cast_as::<EmptyClassWithNew>().is_ok());
}
#[py::class]
@ -107,7 +105,8 @@ fn new_with_one_arg() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<NewWithOneArg>();
let obj = typeobj.call((42,), None).unwrap().cast_into::<NewWithOneArg>().unwrap();
let wrp = typeobj.call((42,), None).unwrap();
let obj = wrp.cast_as::<NewWithOneArg>().unwrap();
assert_eq!(obj._data, 42);
}
@ -132,7 +131,8 @@ fn new_with_two_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<NewWithTwoArgs>();
let obj = typeobj.call((10, 20), None).unwrap().cast_into::<NewWithTwoArgs>().unwrap();
let wrp = typeobj.call((10, 20), None).unwrap();
let obj = wrp.cast_as::<NewWithTwoArgs>().unwrap();
assert_eq!(obj._data1, 10);
assert_eq!(obj._data2, 20);
}
@ -316,7 +316,7 @@ impl StaticMethod {
#[py::class]
struct GCIntegration {
self_ref: RefCell<PyPtr<PyObject>>,
self_ref: RefCell<PyPtr<PyObjectMarker>>,
dropped: TestDropCall,
token: PythonToken<GCIntegration>,
}
@ -328,7 +328,7 @@ impl PyGCProtocol for GCIntegration {
}
fn __clear__(&mut self, py: Python) {
*self.self_ref.borrow_mut() = self.token.None();
*self.self_ref.borrow_mut() = py.None();
}
}
@ -339,7 +339,7 @@ fn gc_integration() {
let drop_called = Arc::new(AtomicBool::new(false));
let mut inst = py.with_token(|t| GCIntegration{
self_ref: RefCell::new(t.None()),
self_ref: RefCell::new(py.None()),
dropped: TestDropCall { drop_called: drop_called.clone() },
token: t});
@ -422,7 +422,7 @@ impl<'p> PyObjectProtocol<'p> for StringMethods {
// Ok(PyString::new(py, "unicode"))
//}
fn __bytes__(&self, py: Python) -> PyResult<Py<PyBytes>> {
fn __bytes__(&self, py: Python) -> PyResult<PyBytes<'p>> {
Ok(PyBytes::new(py, b"bytes"))
}
}
@ -707,35 +707,35 @@ impl PyObjectProtocol for BinaryArithmetic {
#[py::proto]
impl PyNumberProtocol for BinaryArithmetic {
fn __add__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __add__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} + {:?}", self, rhs))
}
fn __sub__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __sub__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} - {:?}", self, rhs))
}
fn __mul__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __mul__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} * {:?}", self, rhs))
}
fn __lshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __lshift__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} << {:?}", self, rhs))
}
fn __rshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __rshift__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} >> {:?}", self, rhs))
}
fn __and__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __and__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} & {:?}", self, rhs))
}
fn __xor__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __xor__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} ^ {:?}", self, rhs))
}
fn __or__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __or__(&self, py: Python, rhs: &PyObject<'p>) -> PyResult<String> {
Ok(format!("{:?} | {:?}", self, rhs))
}
}
@ -778,7 +778,7 @@ impl PyObjectProtocol for RichComparisons {
Ok("RC")
}
fn __richcmp__(&self, py: Python, other: &PyObject, op: CompareOp) -> PyResult<String> {
fn __richcmp__(&self, py: Python, other: &PyObject<'p>, op: CompareOp) -> PyResult<String> {
match op {
CompareOp::Lt => Ok(format!("{:?} < {:?}", self.__repr__(py), other)),
CompareOp::Le => Ok(format!("{:?} <= {:?}", self.__repr__(py), other)),
@ -802,11 +802,11 @@ impl PyObjectProtocol for RichComparisons2 {
}
fn __richcmp__(&self, py: Python,
other: &PyObject, op: CompareOp) -> PyResult<PyPtr<PyObject>> {
other: &'p PyObject<'p>, op: CompareOp) -> PyResult<PyPtr<PyObjectMarker>> {
match op {
CompareOp::Eq => Ok(true.to_object(py.token()).into_object()),
CompareOp::Ne => Ok(false.to_object(py.token()).into_object()),
_ => Ok(py.token().NotImplemented())
CompareOp::Eq => Ok(true.to_object(py).into_object()),
CompareOp::Ne => Ok(false.to_object(py).into_object()),
_ => Ok(py.NotImplemented())
}
}
}
@ -952,10 +952,12 @@ fn inplace_operations() {
#[py::class]
struct ContextManager {
exit_called: bool,
#[token]
token: PythonToken<ContextManager>,
}
/*
#[py::proto]
impl<'p> PyContextProtocol<'p> for ContextManager {
@ -964,19 +966,19 @@ impl<'p> PyContextProtocol<'p> for ContextManager {
}
fn __exit__(&mut self, py: Python,
ty: Option<&'p PyType>,
value: Option<&'p PyObject>,
traceback: Option<&'p PyObject>) -> PyResult<bool> {
ty: Option<PyType<'p>>,
value: Option<PyObject<'p>>,
traceback: Option<PyObject<'p>>) -> PyResult<bool> {
self.exit_called = true;
if ty == Some(py.get_type::<exc::ValueError>()) {
Ok(true)
} else {
Ok(false)
Ok(false)
}
}
}*/
}
/*#[test]
#[test]
fn context_manager() {
let gil = Python::acquire_gil();
let py = gil.python();
@ -994,7 +996,7 @@ fn context_manager() {
py, c, "with c as x:\n raise NotImplementedError",
NotImplementedError);
assert!(c.exit_called);
}*/
}
#[py::class]

View File

@ -24,19 +24,18 @@ fn test_basics() {
struct Test {}
#[py::proto]
impl<'p> PyMappingProtocol<'p> for Test {
fn __getitem__(&self, idx: Py<'p, PyObject>) -> PyResult<Py<'p, PyObject>> {
let py = self.py();
impl<'p> PyMappingProtocol<'p> for Test
{
fn __getitem__(&self, py: Python, idx: PyObject<'p>) -> PyResult<PyPtr<PyObjectMarker>> {
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".to_object(py).into_object())
return Ok("slice".to_object(py))
}
}
else if let Ok(idx) = idx.extract::<isize>() {
if idx == 1 {
return Ok("int".to_object(py).into_object())
return Ok("int".to_object(py))
}
}
Err(PyErr::new::<exc::ValueError, _>(py, "error"))
@ -48,7 +47,7 @@ fn test_cls_impl() {
let gil = Python::acquire_gil();
let py = gil.python();
let ob = py.init(Test{});
let ob = py.with_token(|e| Test{});
let d = PyDict::new(py);
d.set_item("ob", ob).unwrap();