added pptr pointer

This commit is contained in:
Nikolay Kim 2017-05-28 21:19:29 -07:00
parent 969cba2c16
commit 55d0d58734
30 changed files with 832 additions and 306 deletions

View file

@ -41,7 +41,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
const #dummy_const: () = {
extern crate pyo3 as _pyo3;
use std;
use pyo3::python::PythonObjectWithToken;
use pyo3::PythonObjectWithToken;
use pyo3::python::PythonObjectWithCheckedDowncast;
#tokens
};
@ -53,7 +54,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
let extra = if let Some(token) = token {
Some(quote! {
impl _pyo3::python::PythonObjectWithToken for #cls {
impl _pyo3::PythonObjectWithToken for #cls {
fn token<'p>(&'p self) -> _pyo3::python::Python<'p> {
self.#token.token()
}
@ -63,9 +64,10 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let repr = unsafe {
_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
PyString::downcast_from_owned_ptr(
self.token(), _pyo3::ffi::PyObject_Repr(ptr))
.map_err(|_| std::fmt::Error)? };
.map_err(|_| std::fmt::Error)?
};
f.write_str(&repr.to_string_lossy())
}
}
@ -73,11 +75,12 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
impl std::fmt::Display for #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let s = unsafe {
_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
self.token(), _pyo3::ffi::PyObject_Str(ptr)
).map_err(|_| std::fmt::Error)?};
f.write_str(&s.to_string_lossy())
let str_obj = unsafe {
PyString::downcast_from_owned_ptr(
self.token(), _pyo3::ffi::PyObject_Str(ptr))
.map_err(|_| std::fmt::Error)?
};
f.write_str(&str_obj.to_string_lossy())
}
}
})

View file

@ -20,8 +20,8 @@
//! See also the macros `py_argparse!`, `py_fn!` and `py_method!`.
use ffi;
use pyptr::{Py};
use python::{Python, PythonObjectWithToken};
use pyptr::Py;
use python::Python;
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::RefFromPyObject;
use err::{self, PyResult};
@ -44,9 +44,9 @@ 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 PyDict>,
args: &'p PyTuple, kwargs: Option<&'p Py<'p, PyDict>>,
accept_args: bool, accept_kwargs: bool,
output: &mut[Option<&'p PyObject>]) -> PyResult<()>
output: &mut[Option<PyObject<'p>>]) -> PyResult<()>
{
assert!(params.len() == output.len());

View file

@ -12,7 +12,8 @@ use ::{Py, CompareOp};
use ffi;
use err::{PyErr, PyResult};
use python::{Python, IntoPythonPointer};
use objects::{exc, PyObject};
use objects::PyObject;
use objects::exc;
use typeob::PyTypeInfo;
use conversion::{ToPyObject, FromPyObject, IntoPyObject};
use callback::{PyObjectCallbackConverter, HashConverter, BoolCallbackConverter};

View file

@ -10,7 +10,7 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use python::Python;
use objects::{PyObject, PyType};
use objects::{PyType, PyObject};
use callback::{PyObjectCallbackConverter, UnitCallbackConverter};
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;

View file

@ -6,7 +6,8 @@
use ffi;
use err::{PyErr, PyResult};
use python::Python;
use objects::{exc, PyObject};
use objects::exc;
use objects::PyObject;
use callback::{PyObjectCallbackConverter, LenResultConverter};
use conversion::{ToPyObject, FromPyObject};
use typeob::PyTypeInfo;

View file

@ -42,3 +42,5 @@ pub enum CompareOp {
Gt = ffi::Py_GT as isize,
Ge = ffi::Py_GE as isize
}
pub trait PyCustomObject : Sized {}

View file

@ -8,7 +8,8 @@ use std::os::raw::c_int;
use ffi;
use python::Python;
use err::{PyErr, PyResult};
use objects::{exc, PyObject};
use objects::exc;
use objects::PyObject;
use callback::{PyObjectCallbackConverter, LenResultConverter, BoolCallbackConverter};
use typeob::PyTypeInfo;
use conversion::{ToPyObject, IntoPyObject, FromPyObject};

View file

@ -3,14 +3,14 @@ use err::PyResult;
use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer};
use objects::{PyObject, PyTuple};
use typeob::{PyTypeInfo};
use token::PyObjectMarker;
/// Conversion trait that allows various objects to be converted into PyObject
pub trait ToPyObject {
/// Converts self into a Python object.
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObject>;
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObjectMarker>;
/// Converts self into a Python object and calls the specified closure
/// on the native FFI pointer underlying the Python object.
@ -30,7 +30,7 @@ pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self)
#[inline]
fn into_object(self, py: Python) -> PyPtr<PyObject>
fn into_object(self, py: Python) -> PyPtr<PyObjectMarker>
where Self: Sized;
}
@ -39,7 +39,7 @@ pub trait IntoPyObject {
pub trait ToPyTuple {
/// Converts self into a PyTuple object.
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyPtr<PyTuple>;
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p>;
/// Converts self into a PyTuple object and calls the specified closure
/// on the native FFI pointer underlying the Python object.
@ -75,8 +75,7 @@ pub trait ToPyTuple {
/// the inherent method `PyObject::extract()` can be used.
pub trait FromPyObject<'source> : Sized {
/// Extracts `Self` from the source `PyObject`.
fn extract<S>(py: &'source Py<'source, S>) -> PyResult<Self>
where S: PyTypeInfo;
fn extract(py: &'source PyObject<'source>) -> PyResult<Self>;
}
pub trait RefFromPyObject<'p> {
@ -102,7 +101,7 @@ impl <'p, T: ?Sized> RefFromPyObject<'p> for T
impl<T> IntoPyObject for T where T: ToPyObject
{
#[inline]
default fn into_object(self, py: Python) -> PyPtr<PyObject> where Self: Sized
default fn into_object(self, py: Python) -> PyPtr<PyObjectMarker>
{
self.to_object(py)
}
@ -114,7 +113,7 @@ impl<T> IntoPyObject for T where T: ToPyObject
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
#[inline]
default fn to_object(&self, py: Python) -> PyPtr<PyObject> {
default fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
<T as ToPyObject>::to_object(*self, py)
}
@ -130,7 +129,7 @@ impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
/// `Option::None` is converted to Python `None`.
impl <T> ToPyObject for Option<T> where T: ToPyObject {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
match *self {
Some(ref val) => val.to_object(py),
None => py.None()
@ -140,7 +139,7 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
fn into_object(self, py: Python) -> PyPtr<PyObject> {
fn into_object(self, py: Python) -> PyPtr<PyObjectMarker> {
match self {
Some(val) => val.into_object(py),
None => py.None()
@ -151,15 +150,14 @@ impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
/// `()` is converted to Python `None`.
impl ToPyObject for () {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
py.None()
}
}
impl <'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source> {
fn extract<S>(obj: &'source Py<'source, S>) -> PyResult<Self>
where S: PyTypeInfo
fn extract(obj: &'source PyObject) -> PyResult<Self>
{
if obj.as_ptr() == unsafe { ffi::Py_None() } {
Ok(None)

View file

@ -6,8 +6,9 @@ use ffi;
use pyptr::{Py, PyPtr};
use python::{ToPythonPointer, IntoPythonPointer, Python};
use objects::{PyObject, PyType, exc};
use token::PyObjectMarker;
use typeob::{PyTypeObject};
use conversion::{ToPyObject, ToPyTuple};
use conversion::{ToPyObject, ToPyTuple, IntoPyObject};
/**
Defines a new exception type.
@ -91,9 +92,9 @@ pub struct PyErr {
/// 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<PyObject>>,
pub pvalue: Option<PyPtr<PyObjectMarker>>,
/// The `PyTraceBack` object associated with the error.
pub ptraceback: Option<PyPtr<PyObject>>,
pub ptraceback: Option<PyPtr<PyObjectMarker>>,
}
@ -184,7 +185,7 @@ impl PyErr {
}
}
fn new_helper(_py: Python, ty: PyPtr<PyType>, value: PyPtr<PyObject>) -> PyErr {
fn new_helper(_py: Python, ty: PyPtr<PyType>, value: PyPtr<PyObjectMarker>) -> PyErr {
assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0);
PyErr {
ptype: ty,
@ -202,7 +203,7 @@ impl PyErr {
PyErr::from_instance_helper(py, obj.to_object(py))
}
fn from_instance_helper<'p>(py: Python, obj: PyPtr<PyObject>) -> 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(
@ -229,7 +230,7 @@ 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<PyObject>>) -> PyErr {
pub fn new_lazy_init(exc: PyPtr<PyType>, value: Option<PyPtr<PyObjectMarker>>) -> PyErr {
PyErr {
ptype: exc,
pvalue: value,
@ -248,7 +249,7 @@ impl PyErr {
let pval = args.to_py_tuple(py);
PyErr {
ptype: exc.into_pptr(),
pvalue: Some(pval.into_object()),
pvalue: Some(pval.into_object(py)),
ptraceback: None
}
}
@ -307,11 +308,11 @@ impl PyErr {
/// 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<'p>(&mut self, py: Python<'p>) -> Py<'p, PyObject> {
pub fn instance<'p>(&mut self, py: Python<'p>) -> PyObject<'p> {
self.normalize(py);
match self.pvalue {
Some(ref instance) => instance.as_ref(py),
None => py.None().as_ref(py),
Some(ref instance) => instance.as_ref(py).into_pyobject(),
None => py.None().as_ref(py).into_pyobject(),
}
}

View file

@ -861,3 +861,7 @@ pub const Py_NE : c_int = 3;
pub const Py_GT : c_int = 4;
pub const Py_GE : c_int = 5;
pub fn PyObject_Check(_arg1: *mut PyObject) -> c_int {
1
}

View file

@ -67,10 +67,16 @@ pub use ffi::{Py_ssize_t, Py_hash_t};
pub mod pyptr;
pub use pyptr::{Py, PyPtr};
mod ppptr;
pub use ppptr::pptr;
mod token;
pub use token::{PyObjectMarker, PythonToken, PythonObjectWithToken};
pub use err::{PyErr, PyResult, PyDowncastError};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use python::{Python, PythonToken, IntoPythonPointer, PythonObjectWithToken};
pub use python::{Python, IntoPythonPointer};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple};
pub use class::{CompareOp};
@ -106,6 +112,7 @@ macro_rules! py_replace_expr {
}
pub mod python;
pub mod native;
mod err;
mod conversion;
mod objects;

31
src/native.rs Normal file
View file

@ -0,0 +1,31 @@
// use python::{Python, ToPythonPointer, PythonObjectWithCheckedDowncast};
// use err::{PyErr, PyResult};
// use ppptr::pptr;
// use pyptr::Py;
use typeob::PyTypeInfo;
// use conversion::{ToPyObject, FromPyObject};
pub trait PyNativeObject : PyTypeInfo {}
/*impl<'a, T: Sized> FromPyObject<'a> for T
where T: PyNativeObject + PythonObjectWithCheckedDowncast
{
/// Extracts `Self` from the source `Py<PyObject>`.
fn extract<S>(py: &'a Py<'a, S>) -> PyResult<Self> where S: PyTypeInfo
{
<T as PythonObjectWithCheckedDowncast>
::downcast_from(py.clone_ref()).map_err(|e| e.into())
}
}*/
/*impl<T> ::IntoPyObject for T where T: PyNativeObject
{
#[inline]
default fn into_object(self, py: Python) -> ::PyPtr<PyObject>
{
unsafe { ::std::mem::transmute(self) }
}
}*/

View file

@ -7,8 +7,9 @@ use std::cmp::Ordering;
use ffi;
use libc;
use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer, PythonObjectWithToken};
use python::{Python, ToPythonPointer};
use objects::{PyObject, PyDict, PyString};
use token::PythonObjectWithToken;
use conversion::{ToPyObject, ToPyTuple};
use typeob::PyTypeInfo;
use err::{PyErr, PyResult, self};
@ -220,7 +221,7 @@ impl<T> ObjectProtocol for T where T: PythonObjectWithToken + ToPythonPointer {
-> PyResult<Py<PyObject>> where O: ToPyObject {
unsafe {
other.with_borrowed_ptr(self.token(), |other| {
Py::cast_from_owned_nullptr(
Py::cast_from_owned_or_err(
self.token(), ffi::PyObject_RichCompare(
self.as_ptr(), other, compare_op as libc::c_int))
})
@ -231,14 +232,14 @@ impl<T> ObjectProtocol for T where T: PythonObjectWithToken + ToPythonPointer {
/// This is equivalent to the Python expression 'repr(self)'.
#[inline]
fn repr(&self) -> PyResult<Py<PyString>> {
unsafe { Py::cast_from_owned_nullptr(self.token(), ffi::PyObject_Repr(self.as_ptr())) }
unsafe { Py::cast_from_owned_or_err(self.token(), ffi::PyObject_Repr(self.as_ptr())) }
}
/// Compute the string representation of self.
/// This is equivalent to the Python expression 'str(self)'.
#[inline]
fn str(&self) -> PyResult<Py<PyString>> {
unsafe { Py::cast_from_owned_nullptr(self.token(), ffi::PyObject_Str(self.as_ptr())) }
unsafe { Py::cast_from_owned_or_err(self.token(), ffi::PyObject_Str(self.as_ptr())) }
}
/// Determines whether this object is callable.

View file

@ -1,17 +1,18 @@
use ::{PyPtr, PyObject};
use ::{pptr, PyPtr};
use ffi;
use python::{PythonToken, ToPythonPointer, Python};
use conversion::{ToPyObject};
use token::PyObjectMarker;
use python::{ToPythonPointer, Python};
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `bool`.
pub struct PyBool(PythonToken<PyBool>);
pub struct PyBool<'p>(pptr<'p>);
pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type);
pyobject_nativetype!(PyBool, PyBool_Check, PyBool_Type);
impl PyBool {
impl<'p> PyBool<'p> {
/// Depending on `val`, returns `py.True()` or `py.False()`.
#[inline]
pub fn get(py: Python, val: bool) -> PyPtr<PyBool> {
pub fn get(py: Python<'p>, val: bool) -> PyBool<'p> {
if val { py.True() } else { py.False() }
}
@ -25,8 +26,8 @@ impl PyBool {
/// Converts a rust `bool` to a Python `bool`.
impl ToPyObject for bool {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyBool::get(py, *self).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyBool::get(py, *self).into_object(py)
}
#[inline]

View file

@ -4,35 +4,38 @@ use std;
use std::ptr;
use std::os::raw::c_char;
use ffi;
use python::{PythonToken, ToPythonPointer, Python, PythonObjectWithToken};
use python::{Python, ToPythonPointer};
use objects::PyObject;
use err::{PyResult, PyErr};
use pyptr::Py;
use ppptr::pptr;
/// Represents a Python bytearray.
pub struct PyByteArray(PythonToken<PyByteArray>);
pub struct PyByteArray<'p>(pptr<'p>);
pyobject_newtype!(PyByteArray, PyByteArray_Check, PyByteArray_Type);
pyobject_nativetype!(PyByteArray, PyByteArray_Check, PyByteArray_Type);
impl PyByteArray {
impl<'p> PyByteArray<'p> {
/// Creates a new Python bytearray object.
/// The byte string is initialized by copying the data from the `&[u8]`.
///
/// Panics if out of memory.
pub fn new<'p>(py: Python<'p>, src: &[u8]) -> Py<'p, PyByteArray> {
pub fn new<'a>(py: Python<'a>, src: &[u8]) -> PyByteArray<'a> {
let ptr = src.as_ptr() as *const c_char;
let len = src.len() as ffi::Py_ssize_t;
let ptr = unsafe {ffi::PyByteArray_FromStringAndSize(ptr, len)};
unsafe { Py::cast_from_owned_ptr_or_panic(py, ptr) }
unsafe { PyByteArray(pptr::cast_from_owned_ptr_or_panic::<PyByteArray>(py, ptr)) }
}
/// Creates a new Python bytearray object
/// from other PyObject, that implements the buffer protocol.
pub fn from<'p>(src: Py<'p, PyObject>) -> PyResult<Py<'p, PyByteArray>> {
pub fn from(src: Py<'p, PyObject>) -> PyResult<PyByteArray<'p>> {
let res = unsafe {ffi::PyByteArray_FromObject(src.as_ptr())};
if res != ptr::null_mut() {
Ok(unsafe{Py::cast_from_owned_ptr_or_panic(src.token(), res)})
Ok(unsafe{ PyByteArray(
pptr::cast_from_owned_ptr_or_panic::<PyByteArray>(src.token(), res))})
} else {
Err(PyErr::fetch(src.token()))
}
@ -43,15 +46,15 @@ impl PyByteArray {
pub fn len(&self) -> usize {
// non-negative Py_ssize_t should always fit into Rust usize
unsafe {
ffi::PyByteArray_Size(self.as_ptr()) as usize
ffi::PyByteArray_Size(self.0.as_ptr()) as usize
}
}
/// Gets the Python bytearray data as byte slice.
pub fn data(&self) -> &mut [u8] {
unsafe {
let buffer = ffi::PyByteArray_AsString(self.as_ptr()) as *mut u8;
let length = ffi::PyByteArray_Size(self.as_ptr()) as usize;
let buffer = ffi::PyByteArray_AsString(self.0.as_ptr()) as *mut u8;
let length = ffi::PyByteArray_Size(self.0.as_ptr()) as usize;
std::slice::from_raw_parts_mut(buffer, length)
}
}
@ -59,11 +62,11 @@ impl PyByteArray {
/// Resize bytearray object.
pub fn resize(&self, len: usize) -> PyResult<()> {
unsafe {
let result = ffi::PyByteArray_Resize(self.as_ptr(), len as ffi::Py_ssize_t);
let result = ffi::PyByteArray_Resize(self.0.as_ptr(), len as ffi::Py_ssize_t);
if result == 0 {
Ok(())
} else {
Err(PyErr::fetch(self.token()))
Err(PyErr::fetch(self.0.token()))
}
}
}

View file

@ -2,33 +2,37 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ::pptr;
use ffi;
use pyptr::{Py, PyPtr};
use python::{Python, PythonToken, ToPythonPointer, PythonObjectWithToken};
use conversion::ToPyObject;
use objects::{PyObject}; //, PyList};
use pyptr::PyPtr;
use python::{Python, ToPythonPointer};
use conversion::{ToPyObject, IntoPyObject};
use objects::PyObject;
use token::{PyObjectMarker, PythonObjectWithToken}; //, PyList};
use err::{self, PyResult, PyErr};
use std::{mem, collections, hash, cmp};
/// Represents a Python `dict`.
pub struct PyDict(PythonToken<PyDict>);
pub struct PyDict<'p>(pptr<'p>);
pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type);
pyobject_nativetype!(PyDict, PyDict_Check, PyDict_Type);
impl PyDict {
impl<'p> PyDict<'p> {
/// Creates a new empty dictionary.
///
/// May panic when running out of memory.
pub fn new(py: Python) -> Py<PyDict> {
unsafe { Py::from_owned_ptr_or_panic(py, ffi::PyDict_New()) }
pub fn new(py: Python<'p>) -> PyDict<'p> {
unsafe { PyDict(pptr::from_owned_ptr_or_panic(py, ffi::PyDict_New())) }
}
/// Return a new dictionary that contains the same key-value pairs as self.
/// Corresponds to `dict(self)` in Python.
pub fn copy<'p>(&'p self) -> PyResult<PyPtr<PyDict>> {
pub fn copy(&'p self) -> PyResult<PyDict<'p>> {
unsafe {
PyPtr::from_owned_ptr_or_err(self.token(), ffi::PyDict_Copy(self.as_ptr()))
Ok(PyDict(
pptr::from_owned_ptr_or_err(self.token(), ffi::PyDict_Copy(self.0.as_ptr()))?
))
}
}
@ -59,9 +63,10 @@ impl PyDict {
/// Gets an item from the dictionary.
/// 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 {
pub fn get_item<K>(&self, key: K) -> Option<PyObject> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
self.token().from_owned_ptr_opt(ffi::PyDict_GetItem(self.as_ptr(), key))
PyObject::from_owned_ptr_or_opt(
self.token(), ffi::PyDict_GetItem(self.as_ptr(), key))
})
}
@ -117,12 +122,12 @@ impl <K, V> ToPyObject for collections::HashMap<K, V>
where K: hash::Hash+cmp::Eq+ToPyObject,
V: ToPyObject
{
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
let dict = PyDict::new(py);
for (key, value) in self {
dict.set_item(key, value).unwrap();
};
dict.into_object_pptr()
dict.into_object(py)
}
}
@ -130,12 +135,12 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
where K: cmp::Eq+ToPyObject,
V: ToPyObject
{
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
let dict = PyDict::new(py);
for (key, value) in self {
dict.set_item(key, value).unwrap();
};
dict.into_object_pptr()
dict.into_object(py)
}
}

View file

@ -2,28 +2,27 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use pyptr::Py;
use python::{Python, ToPythonPointer, IntoPythonPointer,
PythonToken, PythonObjectWithToken, PythonTokenApi};
use ::pptr;
use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer, IntoPythonPointer, PythonToken, PythonObjectWithToken};
use objects::PyObject;
use ffi::{self, Py_ssize_t};
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `list`.
pub struct PyList(PythonToken<PyList>);
pub struct PyList<'p>(pptr<'p>);
pyobject_newtype!(PyList, PyList_Check, PyList_Type);
pyobject_nativetype!(PyList, PyList_Check, PyList_Type);
impl PyList {
impl<'p> PyList<'p> {
/// Construct a new list with the given elements.
pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> Py<'p, PyList> {
pub fn new<T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyList<'p> {
unsafe {
let ptr = ffi::PyList_New(elements.len() as Py_ssize_t);
let t = Py::<PyList>::cast_from_owned_ptr_or_panic(py, ptr);
for (i, e) in elements.iter().enumerate() {
ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr());
}
t
PyList(pptr::from_owned_ptr_or_panic(py, ptr))
}
}
@ -51,7 +50,7 @@ impl PyList {
/// Sets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn set_item<'p>(&self, index: usize, item: Py<'p, PyObject>) {
pub fn set_item(&self, index: usize, item: Py<'p, PyObject>) {
let r = unsafe { ffi::PyList_SetItem(
self.as_ptr(), index as Py_ssize_t, item.into_ptr()) };
assert!(r == 0);
@ -60,20 +59,20 @@ impl PyList {
/// Inserts an item at the specified index.
///
/// Panics if the index is out of range.
pub fn insert_item<'p>(&self, index: usize, item: Py<'p, PyObject>) {
pub fn insert_item(&self, index: usize, item: Py<'p, PyObject>) {
let r = unsafe { ffi::PyList_Insert(self.as_ptr(), index as Py_ssize_t, item.as_ptr()) };
assert!(r == 0);
}
#[inline]
pub fn iter<'p>(&'p self) -> PyListIterator<'p> {
pub fn iter(&'p self) -> PyListIterator<'p> {
PyListIterator { list: self, index: 0 }
}
}
/// Used by `PyList::iter()`.
pub struct PyListIterator<'p> {
list: &'p PyList,
list: &'p PyList<'p>,
index: usize
}
@ -81,7 +80,7 @@ impl <'p> Iterator for PyListIterator<'p> {
type Item = Py<'p, PyObject>;
#[inline]
fn next(&mut self) -> Option<Py<'p, PyObject>> {
fn next(&mut self) -> Option<&'p PyObject> {
if self.index < self.list.len() {
let item = self.list.get_item(self.index);
self.index += 1;
@ -97,22 +96,21 @@ impl <'p> Iterator for PyListIterator<'p> {
impl <T> ToPyObject for [T] where T: ToPyObject {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
unsafe {
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
let t = Py::cast_from_owned_ptr_or_panic(py, ptr);
for (i, e) in self.iter().enumerate() {
let obj = e.to_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
t
PyPtr::from_owned_ptr_or_panic(ptr)
}
}
}
impl <T> ToPyObject for Vec<T> where T: ToPyObject {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> {
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObject> {
self.as_slice().to_object(py)
}
@ -120,15 +118,14 @@ impl <T> ToPyObject for Vec<T> where T: ToPyObject {
impl <T> IntoPyObject for Vec<T> where T: IntoPyObject {
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> {
fn into_object(self, py: Python) -> PyPtr<PyObject> {
unsafe {
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
let t = Py::from_owned_ptr_or_panic(py, ptr);
for (i, e) in self.into_iter().enumerate() {
let obj = e.into_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
t
PyPtr::from_owned_ptr_or_panic(ptr)
}
}
}

View file

@ -43,7 +43,7 @@ macro_rules! pyobject_newtype(
}
}
impl $crate::python::PythonObjectWithToken for $name {
impl $crate::token::PythonObjectWithToken for $name {
fn token<'p>(&'p self) -> $crate::python::Python<'p> {
self.0.token()
}
@ -53,8 +53,8 @@ macro_rules! pyobject_newtype(
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = <$name as $crate::python::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
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));
@ -66,8 +66,8 @@ macro_rules! pyobject_newtype(
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = <$name as $crate::python::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
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));
@ -77,13 +77,160 @@ macro_rules! pyobject_newtype(
);
);
#[macro_export]
macro_rules! pyobject_nativetype(
($name: ident, $checkfunction: ident, $typeobject: ident) => (
impl<'p> $crate::native::PyNativeObject for $name<'p> {}
impl<'p> $crate::typeob::PyTypeInfo for $name<'p> {
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<'p> $crate::token::PythonObjectWithToken for $name<'p> {
fn token<'a>(&'a self) -> $crate::python::Python<'a> {
self.0.token()
}
}
impl<'p> $crate::python::PythonObjectWithCheckedDowncast<'p> for $name<'p>
{
fn downcast_from(py: $crate::Py<'p, $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)
}
fn downcast_from_owned_ptr(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject)
-> Result<$name<'p>, $crate::PyDowncastError<'p>>
{
Ok($name($crate::pptr::cast_from_owned_ptr::<$name>(py, ptr)?))
}
}
impl<'p> $crate::python::ToPythonPointer for $name<'p> {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self.0.as_ptr()
}
}
impl<'a> $crate::FromPyObject<'a> for $name<'a>
{
/// Extracts `Self` from the source `Py<PyObject>`.
fn extract(py: &'a $crate::PyObject<'a>) -> $crate::PyResult<Self>
//where S: $crate::typeob::PyTypeInfo
{
use $crate::token::PythonObjectWithToken;
Ok($name(
$crate::pptr::cast_from_borrowed_ptr::<$name>(py.token(), py.as_ptr())?))
}
}
impl<'a> $crate::FromPyObject<'a> for &'a $name<'a>
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: &'a $crate::PyObject<'a>) -> $crate::PyResult<Self>
//where S: $crate::typeob::PyTypeInfo
{
unsafe {
if ffi::$checkfunction(py.as_ptr()) != 0 {
Ok($crate::std::mem::transmute(py))
} else {
Err($crate::PyDowncastError(
$crate::token::PythonObjectWithToken::token(py), None).into())
}
}
}
}
impl<'a> $crate::ToPyObject for $name<'a>
{
#[inline]
default fn to_object<'p>(&self, _py: $crate::Python<'p>)
-> $crate::PyPtr<$crate::PyObjectMarker> {
unsafe { $crate::PyPtr::from_borrowed_ptr(self.0.as_ptr()) }
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
f(self.0.as_ptr())
}
}
impl<'a> $crate::IntoPyObject for $name<'a>
{
#[inline]
fn into_object(self, _py: $crate::Python) -> $crate::PyPtr<$crate::PyObjectMarker>
{
unsafe { $crate::std::mem::transmute(self) }
}
}
impl<'p> $crate::std::fmt::Debug for $name<'p> {
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
use python::PythonObjectWithCheckedDowncast;
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))) };
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
f.write_str(&repr_obj.to_string_lossy())
}
}
impl<'p> $crate::std::fmt::Display for $name<'p> {
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_rules! pyobject_extract(
($obj:ident to $t:ty => $body: block) => {
impl<'source> ::conversion::FromPyObject<'source>
for $t
{
fn extract<S>($obj: &'source ::Py<'source, S>) -> $crate::PyResult<Self>
where S: ::typeob::PyTypeInfo
fn extract($obj: &'source ::PyObject<'source>) -> $crate::PyResult<Self>
//where S: ::typeob::PyTypeInfo
{
$body
}

View file

@ -7,32 +7,39 @@ use ffi;
use std::os::raw::c_char;
use std::ffi::{CStr, CString};
use pyptr::{Py, PyPtr};
use python::{PythonToken, ToPythonPointer, PythonObjectWithToken, Python};
use ::pptr;
use pyptr::PyPtr;
use python::{ToPythonPointer, Python};
use token::PythonObjectWithToken;
use objects::{PyDict, PyType, exc};
use objectprotocol::ObjectProtocol;
use err::{PyResult, PyErr};
/// Represents a Python module object.
pub struct PyModule(PythonToken<PyModule>);
pub struct PyModule<'p>(pptr<'p>);
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
pyobject_nativetype!(PyModule, PyModule_Check, PyModule_Type);
impl PyModule {
impl<'p> PyModule<'p> {
/// Create a new module object with the `__name__` attribute set to name.
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<Py<'p, PyModule>> {
pub fn new(py: Python<'p>, name: &str) -> PyResult<PyModule<'p>> {
let name = CString::new(name).unwrap();
unsafe {
Py::cast_from_owned_nullptr(py, ffi::PyModule_New(name.as_ptr()))
let ptr = pptr::cast_from_owned_nullptr::<PyModule>(
py, ffi::PyModule_New(name.as_ptr()))?;
Ok(PyModule(ptr))
}
}
/// Import the Python module with the specified name.
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<Py<'p, PyModule>> {
pub fn import(py: Python<'p>, name: &str) -> PyResult<PyModule<'p>> {
let name = CString::new(name).unwrap();
unsafe {
Py::cast_from_owned_nullptr(py, ffi::PyImport_ImportModule(name.as_ptr()))
let ptr = pptr::cast_from_owned_nullptr::<PyModule>(
py, ffi::PyImport_ImportModule(name.as_ptr()))?;
Ok(PyModule(ptr))
}
}
@ -52,7 +59,8 @@ impl PyModule {
match std::str::from_utf8(slice) {
Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance(
self.token(), try!(exc::UnicodeDecodeError::new_utf8(self.token(), slice, e))))
self.token(),
try!(exc::UnicodeDecodeError::new_utf8(self.token(), slice, e))))
}
}
}
@ -76,7 +84,7 @@ impl PyModule {
/// This is a convenience function that initializes the `class`,
/// sets `new_type.__module__` to this module's name,
/// and adds the type to this module.
pub fn add_class<'p, T>(&self) -> PyResult<()>
pub fn add_class<T>(&self) -> PyResult<()>
where T: ::typeob::PyTypeInfo
{
let mut ty = <T as ::typeob::PyTypeInfo>::type_object();

View file

@ -7,14 +7,14 @@ extern crate num_traits;
use self::num_traits::cast::cast;
use std::os::raw::{c_long, c_double};
use ::{Py, PyPtr};
use ::{PyPtr, pptr};
use ffi;
use super::exc;
use super::PyObject;
use typeob::PyTypeInfo;
use python::{PythonToken, ToPythonPointer, Python};
use objects::PyObject;
use token::{PyObjectMarker, PythonObjectWithToken};
use python::{ToPythonPointer, Python};
use err::{PyResult, PyErr};
use conversion::{ToPyObject, FromPyObject};
use conversion::{ToPyObject, FromPyObject, IntoPyObject};
/// Represents a Python `int` object.
///
@ -22,8 +22,8 @@ use conversion::{ToPyObject, FromPyObject};
/// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with the primitive Rust integer types.
pub struct PyLong(PythonToken<PyLong>);
pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type);
pub struct PyLong<'p>(pptr<'p>);
pyobject_nativetype!(PyLong, PyLong_Check, PyLong_Type);
/// Represents a Python `float` object.
///
@ -31,21 +31,21 @@ pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type);
/// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with `f32`/`f64`.
pub struct PyFloat(PythonToken<PyFloat>);
pyobject_newtype!(PyFloat, PyFloat_Check, PyFloat_Type);
pub struct PyFloat<'p>(pptr<'p>);
pyobject_nativetype!(PyFloat, PyFloat_Check, PyFloat_Type);
impl PyFloat {
impl<'p> PyFloat<'p> {
/// Creates a new Python `float` object.
pub fn new(_py: Python, val: c_double) -> PyPtr<PyFloat> {
pub fn new(py: Python<'p>, val: c_double) -> PyFloat<'p> {
unsafe {
PyPtr::from_owned_ptr_or_panic(ffi::PyFloat_FromDouble(val))
PyFloat(pptr::from_owned_ptr_or_panic(py, ffi::PyFloat_FromDouble(val)))
}
}
/// Gets the value of this float.
pub fn value(&self) -> c_double {
unsafe { ffi::PyFloat_AsDouble(self.as_ptr()) }
unsafe { ffi::PyFloat_AsDouble(self.0.as_ptr()) }
}
}
@ -53,7 +53,7 @@ impl PyFloat {
macro_rules! int_fits_c_long(
($rust_type:ty) => (
impl ToPyObject for $rust_type {
fn to_object(&self, _py: Python) -> PyPtr<PyObject> {
fn to_object(&self, _py: Python) -> PyPtr<PyObjectMarker> {
unsafe {
PyPtr::from_owned_ptr_or_panic(ffi::PyLong_FromLong(*self as c_long))
}
@ -78,7 +78,7 @@ macro_rules! int_fits_larger_int(
($rust_type:ty, $larger_type:ty) => (
impl ToPyObject for $rust_type {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
(*self as $larger_type).to_object(py)
}
}
@ -109,7 +109,7 @@ macro_rules! int_convert_u64_or_i64 (
($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => (
impl ToPyObject for $rust_type {
fn to_object(&self, _py: Python) -> PyPtr<PyObject> {
fn to_object(&self, _py: Python) -> PyPtr<PyObjectMarker> {
unsafe {
PyPtr::from_owned_ptr_or_panic($pylong_from_ll_or_ull(*self))
}
@ -117,8 +117,8 @@ macro_rules! int_convert_u64_or_i64 (
}
impl<'source> FromPyObject<'source> for $rust_type {
fn extract<S>(py: &'source Py<'source, S>) -> PyResult<$rust_type>
where S: PyTypeInfo
fn extract(py: &'source PyObject) -> PyResult<$rust_type>
//where S: PyTypeInfo
{
let ptr = py.as_ptr();
unsafe {
@ -169,8 +169,8 @@ int_fits_larger_int!(usize, u64);
int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong);
impl ToPyObject for f64 {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyFloat::new(py, *self).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyFloat::new(py, *self).into_object(py)
}
}
@ -188,8 +188,8 @@ fn overflow_error(py: Python) -> PyErr {
}
impl ToPyObject for f32 {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyFloat::new(py, *self as f64).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyFloat::new(py, *self as f64).into_object(py)
}
}

View file

@ -2,64 +2,61 @@
use std;
use ::pptr;
use ffi;
use pyptr::{Py, PyPtr};
use err::{PyDowncastError};
use python::{PythonToken, Python, PythonObjectWithToken};
use err::{PyResult, PyDowncastError};
use python::{Python, ToPythonPointer};
use token::PythonObjectWithToken;
use typeob::PyTypeInfo;
pub struct PyObject(PythonToken<PyObject>);
pyobject_newtype!(PyObject, PyObject_Check, PyBaseObject_Type);
pub struct PyObject<'p>(pptr<'p>);
impl PyObject {
pyobject_nativetype!(PyObject, PyObject_Check, PyBaseObject_Type);
impl<'p> PyObject<'p> {
#[inline]
pub fn from_owned_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<PyObject> {
unsafe { Py::from_owned_ptr(py, ptr) }
pub fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyObject<'p> {
unsafe { PyObject(pptr::from_owned_ptr(py, ptr)) }
}
#[inline]
pub fn from_borrowed_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<PyObject> {
unsafe { Py::from_borrowed_ptr(py, ptr) }
pub fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject)
-> PyResult<PyObject<'p>> {
unsafe { Ok(PyObject(pptr::from_owned_ptr_or_err(py, ptr)?)) }
}
/// Creates a PyObject instance for the given FFI pointer.
/// This moves ownership over the pointer into the PyObject.
/// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline]
pub unsafe fn from_owned_pptr_opt(py: Python, ptr: *mut ffi::PyObject)
-> Option<PyPtr<PyObject>> {
if ptr.is_null() {
None
} else {
Some(PyObject::from_owned_ptr(py, ptr).into_pptr())
pub fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<PyObject<'p>> {
unsafe {
if let Some(ptr) = pptr::from_owned_ptr_or_opt(py, ptr) {
Some(PyObject(ptr))
} else {
None
}
}
}
/// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline]
pub unsafe fn from_borrowed_pptr_opt(py: Python, ptr: *mut ffi::PyObject)
-> Option<PyPtr<PyObject>> {
if ptr.is_null() {
None
} else {
Some(PyObject::from_borrowed_ptr(py, ptr).into_pptr())
}
pub fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyObject<'p> {
unsafe { PyObject(pptr::from_borrowed_ptr(py, ptr)) }
}
/// Transmutes a slice of owned FFI pointers to `&[Py<'p, PyObject>]`.
/// Undefined behavior if any pointer in the slice is NULL or invalid.
#[inline]
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr: &'a [*mut ffi::PyObject])
-> &'a [Py<'a, PyObject>] {
-> &'a [PyObject<'p>] {
std::mem::transmute(ptr)
}
/// 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_as<'p, D>(&'p self) -> Result<&'p D, PyDowncastError<'p>>
pub fn cast_as<D>(&'p self) -> Result<&'p D, PyDowncastError<'p>>
where D: PyTypeInfo
{
unsafe {
@ -74,4 +71,12 @@ impl PyObject {
}
}
}
/// Extracts some type from the Python object.
/// This is a wrapper function around `FromPyObject::extract()`.
#[inline]
pub fn extract<D>(&'p self) -> PyResult<D> where D: ::conversion::FromPyObject<'p>
{
::conversion::FromPyObject::extract(&self)
}
}

View file

@ -1,12 +1,14 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std::os::raw::c_long;
use pyptr::{Py, PyPtr};
use objects::PyObject;
use python::{PythonToken, ToPythonPointer, Python, PythonObjectWithToken};
use ::pptr;
use pyptr::PyPtr;
use python::{ToPythonPointer, Python};
use err::{PyErr, PyResult};
use ffi::{self, Py_ssize_t};
use conversion::ToPyObject;
use conversion::{ToPyObject, IntoPyObject};
use token::{PyObjectMarker, PythonObjectWithToken};
/// Represents a Python `slice` indices
pub struct PySliceIndices {
@ -30,18 +32,19 @@ impl PySliceIndices {
/// Represents a Python `slice`. Only `c_long` indeces supprted
/// at the moment by PySlice object.
pub struct PySlice(PythonToken<PySlice>);
pub struct PySlice<'p>(pptr<'p>);
pyobject_newtype!(PySlice, PySlice_Check, PySlice_Type);
pyobject_nativetype!(PySlice, PySlice_Check, PySlice_Type);
impl<'p> PySlice<'p> {
impl PySlice {
/// Construct a new slice with the given elements.
pub fn new<'p>(py: Python<'p>, start: isize, stop: isize, step: isize) -> Py<'p, PySlice> {
pub fn new(py: Python<'p>, start: isize, stop: isize, step: isize) -> PySlice<'p> {
unsafe {
let ptr = ffi::PySlice_New(ffi::PyLong_FromLong(start as i64),
ffi::PyLong_FromLong(stop as i64),
ffi::PyLong_FromLong(step as i64));
Py::from_owned_ptr_or_panic(py, ptr)
PySlice(pptr::from_owned_ptr_or_panic(py, ptr))
}
}
@ -75,7 +78,7 @@ impl PySlice {
}
impl ToPyObject for PySliceIndices {
fn to_object<'p>(&self, py: Python) -> PyPtr<PyObject> {
PySlice::new(py, self.start, self.stop, self.step).into_object_pptr()
fn to_object<'p>(&self, py: Python) -> PyPtr<PyObjectMarker> {
PySlice::new(py, self.start, self.stop, self.step).into_object(py)
}
}

View file

@ -8,22 +8,23 @@ use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::os::raw::c_char;
use ::{Py, PyPtr};
use ::{Py, PyPtr, pptr};
use ffi;
use python::{PythonToken, ToPythonPointer, Python, PythonObjectWithToken};
use python::{ToPythonPointer, Python};
use super::{exc, PyObject};
use token::{PyObjectMarker, PythonObjectWithToken};
use err::{PyResult, PyErr};
use conversion::{ToPyObject, RefFromPyObject};
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject};
/// Represents a Python string.
pub struct PyString(PythonToken<PyString>);
pub struct PyString<'p>(pptr<'p>);
pyobject_newtype!(PyString, PyUnicode_Check, PyUnicode_Type);
pyobject_nativetype!(PyString, PyUnicode_Check, PyUnicode_Type);
/// Represents a Python byte string.
pub struct PyBytes(PythonToken<PyBytes>);
pub struct PyBytes<'p>(pptr<'p>);
pyobject_newtype!(PyBytes, PyBytes_Check, PyBytes_Type);
pyobject_nativetype!(PyBytes, PyBytes_Check, PyBytes_Type);
/// Enum of possible Python string representations.
@ -133,29 +134,29 @@ impl <'a> PyStringData<'a> {
}
}
impl PyString {
impl<'p> PyString<'p> {
/// Creates a new Python string object.
///
/// On Python 2.7, this function will create a byte string if the
/// input string is ASCII-only; and a unicode string otherwise.
/// Use `PyUnicode::new()` to always create a unicode string.
///
/// Panics if out of memory.
pub fn new<'p>(_py: Python, s: &str) -> PyPtr<PyString> {
pub fn new(py: Python<'p>, s: &str) -> PyString<'p> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
PyPtr::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
PyString(pptr::from_owned_ptr_or_panic(
py, ffi::PyUnicode_FromStringAndSize(ptr, len)))
}
}
pub fn from_object<'p>(src: &PyObject, encoding: &str, errors: &str)
-> PyResult<PyPtr<PyString>> {
pub fn from_object(src: &'p PyObject, encoding: &str, errors: &str)
-> PyResult<PyString<'p>> {
unsafe {
PyPtr::from_owned_ptr_or_err(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8))
.map_err(|e| e.into())
Ok(PyString(
pptr::from_owned_ptr_or_err(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?))
}
}
@ -191,17 +192,17 @@ impl PyString {
}
}
impl PyBytes {
impl<'p> PyBytes<'p> {
/// Creates a new Python byte string object.
/// The byte string is initialized by copying the data from the `&[u8]`.
///
/// Panics if out of memory.
pub fn new<'p>(py: Python<'p>, s: &[u8]) -> Py<'p, PyBytes> {
pub fn new(py: Python<'p>, s: &[u8]) -> PyBytes<'p> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
Py::cast_from_owned_ptr_or_panic(
py, ffi::PyBytes_FromStringAndSize(ptr, len))
PyBytes(pptr::from_owned_ptr_or_panic(
py, ffi::PyBytes_FromStringAndSize(ptr, len)))
}
}
@ -219,8 +220,8 @@ impl PyBytes {
/// See `PyString::new` for details on the conversion.
impl ToPyObject for str {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyString::new(py, self).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyString::new(py, self).into_object(py)
}
}
@ -228,8 +229,8 @@ impl ToPyObject for str {
/// See `PyString::new` for details on the conversion.
impl <'a> ToPyObject for Cow<'a, str> {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyString::new(py, self).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyString::new(py, self).into_object(py)
}
}
@ -237,8 +238,8 @@ impl <'a> ToPyObject for Cow<'a, str> {
/// See `PyString::new` for details on the conversion.
impl ToPyObject for String {
#[inline]
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyString::new(py, self).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyString::new(py, self).into_object(py)
}
}

View file

@ -4,38 +4,39 @@
use std::slice;
use ::{Py, PyPtr};
use ::{PyPtr, pptr};
use ffi::{self, Py_ssize_t};
use python::{PythonToken, Python,
ToPythonPointer, IntoPythonPointer, PythonObjectWithToken};
use err::{PyErr, PyResult};
use conversion::{FromPyObject, ToPyObject, ToPyTuple};
use python::{Python, ToPythonPointer, IntoPythonPointer};
use conversion::{FromPyObject, ToPyObject, ToPyTuple, IntoPyObject};
use objects::PyObject;
use token::{PyObjectMarker, PythonObjectWithToken};
use super::exc;
use super::PyObject;
/// Represents a Python tuple object.
pub struct PyTuple(PythonToken<PyTuple>);
pub struct PyTuple<'p>(pptr<'p>);
pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);
pyobject_nativetype!(PyTuple, PyTuple_Check, PyTuple_Type);
impl<'p> PyTuple<'p> {
impl PyTuple {
/// Construct a new tuple with the given elements.
pub fn new<'p, T: ToPyObject>(py: Python, elements: &[T]) -> PyPtr<PyTuple> {
pub fn new<T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyTuple<'p> {
unsafe {
let len = elements.len();
let ptr = ffi::PyTuple_New(len as Py_ssize_t);
let t = PyPtr::from_owned_ptr_or_panic(ptr);
for (i, e) in elements.iter().enumerate() {
ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr());
}
t
PyTuple(pptr::from_owned_ptr_or_panic(py, ptr))
}
}
/// Retrieves the empty tuple.
pub fn empty(_py: Python) -> PyPtr<PyTuple> {
pub fn empty(py: Python<'p>) -> PyTuple<'p> {
unsafe {
PyPtr::from_owned_ptr_or_panic(ffi::PyTuple_New(0))
PyTuple(pptr::from_owned_ptr_or_panic(py, ffi::PyTuple_New(0)))
}
}
@ -51,18 +52,18 @@ impl PyTuple {
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_item<'p>(&self, index: usize) -> &PyObject {
pub fn get_item(&'p self, index: usize) -> PyObject<'p> {
// TODO: reconsider whether we should panic
// It's quite inconsistent that this method takes `Python` when `len()` does not.
assert!(index < self.len());
unsafe {
self.token().from_owned_ptr(
ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
PyObject::from_owned_ptr(
self.token(), ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
}
}
#[inline]
pub fn as_slice<'a>(&'a self) -> &'a [Py<'a, PyObject>] {
pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
// This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
// and because tuples are immutable.
// (We don't even need a Python token, thanks to immutability)
@ -81,14 +82,14 @@ impl PyTuple {
//}
}
impl<'a> ToPyTuple for Py<'a, PyTuple> {
fn to_py_tuple(&self, _py: Python) -> PyPtr<PyTuple> {
self.as_pptr()
impl<'a> ToPyTuple for PyTuple<'a> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
unsafe { PyTuple(pptr::from_owned_ptr_or_panic(py, self.0.as_ptr())) }
}
}
impl<'a> ToPyTuple for &'a str {
fn to_py_tuple(&self, py: Python) -> PyPtr<PyTuple> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
PyTuple::new(py, &[py_coerce_expr!(self.to_object(py))])
}
}
@ -102,15 +103,15 @@ fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => {
impl <$($T: ToPyObject),+> ToPyObject for ($($T,)+) {
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObject> {
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObjectMarker> {
PyTuple::new(py, &[
$(py_coerce_expr!(self.$n.to_object(py)),)+
]).into_object()
]).into_object(py)
}
}
impl <$($T: ToPyObject),+> ToPyTuple for ($($T,)+) {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyPtr<PyTuple> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
PyTuple::new(py, &[
$(py_coerce_expr!(self.$n.to_object(py)),)+
])
@ -118,8 +119,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
}
impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) {
fn extract<S>(obj: &'s Py<'s, S>) -> PyResult<Self>
where S: ::typeob::PyTypeInfo
fn extract(obj: &'s PyObject<'s>) -> PyResult<Self>
//where S: ::typeob::PyTypeInfo
{
let t = try!(obj.cast_as::<&PyTuple>());
let slice = t.as_slice();
@ -167,15 +168,15 @@ pub struct NoArgs;
/// Converts `NoArgs` to an empty Python tuple.
impl ToPyObject for NoArgs {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
PyTuple::empty(py).into_object()
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
PyTuple::empty(py).into_object(py)
}
}
/// Converts `NoArgs` to an empty Python tuple.
impl ToPyTuple for NoArgs {
fn to_py_tuple(&self, py: Python) -> PyPtr<PyTuple> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
PyTuple::empty(py)
}
}
@ -183,7 +184,7 @@ impl ToPyTuple for NoArgs {
/// Converts `()` to an empty Python tuple.
impl ToPyTuple for () {
fn to_py_tuple(&self, py: Python) -> PyPtr<PyTuple> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
PyTuple::empty(py)
}
}

View file

@ -7,7 +7,8 @@ use std::borrow::Cow;
use ffi;
use pyptr::{PyPtr};
use python::{Python, PythonToken, ToPythonPointer, PythonObjectWithToken};
use token::{PythonToken, PythonObjectWithToken};
use python::{Python, ToPythonPointer};
use conversion::ToPyTuple;
use objects::{PyObject, PyDict};
use err::PyResult;

178
src/ppptr.rs Normal file
View file

@ -0,0 +1,178 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use ffi;
use err::{PyErr, PyResult};
use python::{Python, ToPythonPointer};
use typeob::{PyTypeInfo, PyObjectAlloc};
pub struct pptr<'p>(Python<'p>, *mut ffi::PyObject);
impl<'p> pptr<'p> {
/// Create new python object and move T instance under python management
pub fn new<T>(py: Python<'p>, value: T) -> PyResult<pptr<'p>> where T: PyObjectAlloc<Type=T>
{
let ptr = unsafe {
try!(<T as PyObjectAlloc>::alloc(py, value))
};
Ok(pptr(py, ptr))
}
/// Creates a Py instance for the given FFI pointer.
/// This moves ownership over the pointer into the Py.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> pptr<'p> {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
pptr(py, ptr)
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> pptr<'p>
{
if ptr.is_null() {
::err::panic_after_error();
} else {
pptr::from_owned_ptr(py, ptr)
}
}
/// Construct pppt<'p> 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.
pub unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject)
-> PyResult<pptr<'p>>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(pptr::from_owned_ptr(py, ptr))
}
}
/// Creates a pptr<'p> instance for the given FFI pointer.
/// 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)
-> Option<pptr<'p>> {
if ptr.is_null() {
None
} else {
Some(pptr::from_owned_ptr(py, ptr))
}
}
/// Creates a Py instance for the given FFI pointer.
/// Calls Py_INCREF() on the ptr.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> pptr<'p> {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr);
pptr(py, ptr)
}
/// 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>> {
if ptr.is_null() {
None
} else {
debug_assert!(ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr);
Some(pptr(py, ptr))
}
}
/// Gets the reference count of this Py object.
#[inline]
pub fn get_refcnt(&self) -> usize {
unsafe { ffi::Py_REFCNT(self.1) as usize }
}
pub fn token<'a>(&'a self) -> Python<'p> {
self.0
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub fn cast_from_owned_ptr<T>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<pptr<'p>, ::PyDowncastError<'p>>
where T: PyTypeInfo
{
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 };
if checked {
Ok( unsafe { pptr::from_owned_ptr(py, ptr) })
} else {
Err(::PyDowncastError(py, None))
}
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub fn cast_from_borrowed_ptr<T>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<pptr<'p>, ::PyDowncastError<'p>>
where T: PyTypeInfo
{
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 };
if checked {
Ok( unsafe { pptr::from_borrowed_ptr(py, ptr) })
} else {
Err(::PyDowncastError(py, None))
}
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub unsafe fn cast_from_owned_ptr_or_panic<T>(py: Python<'p>,
ptr: *mut ffi::PyObject) -> pptr<'p>
where T: PyTypeInfo
{
if ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 {
pptr::from_owned_ptr(py, ptr)
} else {
::err::panic_after_error();
}
}
#[inline]
pub fn cast_from_owned_nullptr<T>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> PyResult<pptr<'p>>
where T: PyTypeInfo
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
pptr::cast_from_owned_ptr::<T>(py, ptr).map_err(|e| e.into())
}
}
}
impl<'p> ToPythonPointer for pptr<'p> {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self.1
}
}
/// Dropping a `pptr` instance decrements the reference count on the object by 1.
impl<'p> Drop for pptr<'p> {
fn drop(&mut self) {
unsafe {
println!("drop pptr: {:?} {} {:?}",
self.1, ffi::Py_REFCNT(self.1), &self as *const _);
}
unsafe { ffi::Py_DECREF(self.1); }
}
}

View file

@ -8,8 +8,9 @@ use std::convert::{AsRef, AsMut};
use ffi;
use err::{PyErr, PyResult, PyDowncastError};
use conversion::{ToPyObject, IntoPyObject};
use python::{Python, ToPythonPointer, IntoPythonPointer};
use objects::PyObject;
use python::{Python, ToPythonPointer, IntoPythonPointer};
use token::{PyObjectMarker, PythonObjectWithToken};
use typeob::{PyTypeInfo, PyObjectAlloc};
@ -28,6 +29,19 @@ impl<T> PyPtr<T> {
PyPtr {inner: ptr, _t: PhantomData}
}
/// Creates a PyObject instance for the given FFI pointer.
/// This moves ownership over the pointer into the PyObject.
/// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline]
pub unsafe fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject)
-> Option<PyPtr<T>> {
if ptr.is_null() {
None
} else {
Some(PyPtr::from_owned_ptr(ptr))
}
}
/// Construct PyPtr<PyObject> from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is `null`.
@ -90,7 +104,7 @@ impl<T> PyPtr<T> {
/// Converts PyPtr<T> -> PyPtr<PyObject>
/// Consumes `self` without calling `Py_INCREF()`
#[inline]
pub fn into_object(self) -> PyPtr<PyObject> {
pub fn into_object(self) -> PyPtr<PyObjectMarker> {
let p = PyPtr {inner: self.inner, _t: PhantomData};
std::mem::forget(self);
p
@ -141,7 +155,7 @@ impl<T> IntoPythonPointer for PyPtr<T> {
impl<T> IntoPyObject for PyPtr<T> {
#[inline]
fn into_object<'a>(self, _py: Python) -> PyPtr<PyObject> {
fn into_object<'a>(self, _py: Python) -> PyPtr<PyObjectMarker> {
self.into_object()
}
}
@ -192,6 +206,17 @@ impl<'p, T> Py<'p, T>
}
}
#[inline]
pub unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<Py<'p, T>>
{
if ptr.is_null() {
None
} else {
Some(Py::from_owned_ptr(py, ptr))
}
}
/// Construct Py<'p, PyObj> from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is `null`.
@ -254,24 +279,28 @@ impl<'p, T> Py<'p, T>
ptr
}
/// Consumes a Py<T> instance and creates a PyPtr<PyObject> instance.
/// Ownership moves over to the PyPtr<T> instance, Does not call Py_INCREF() on the ptr.
#[inline]
pub fn into_object_pptr(self) -> PyPtr<PyObject> {
let ptr = PyPtr { inner: self.inner, _t: PhantomData };
std::mem::forget(self);
ptr
}
/// Converts Py<'p, T> -> Py<'p, PyObject>
/// Consumes `self` without calling `Py_DECREF()`
#[inline]
pub fn into_object(self) -> Py<'p, PyObject> {
pub fn into_object(self) -> Py<'p, PyObjectMarker> {
let p = Py {inner: self.inner, _t: PhantomData, py: self.py};
std::mem::forget(self);
p
}
/// Converts Py<'p, T> -> PyObject<'p>. Calls Py_INCREF() on the ptr.
#[inline]
pub fn as_pyobject(&self) -> &PyObject<'p> {
unsafe { std::mem::transmute(self) }
}
/// Converts Py<'p, T> -> PyObject<'p>
/// Consumes `self` without calling `Py_DECREF()`
#[inline]
pub fn into_pyobject(self) -> PyObject<'p> {
unsafe { std::mem::transmute(self) }
}
/// Unchecked downcast from other Py<S> to Py<S>.
/// Undefined behavior if the input object does not have the expected type.
#[inline]
@ -292,7 +321,6 @@ impl<'p, T> Py<'p, T>
}
}
impl<'p, T> Py<'p, T> where T: PyTypeInfo
{
/// Create new python object and move T instance under python management
@ -332,6 +360,16 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
}
}
pub fn cast_from_owned_or_err(py: Python<'p>, ptr: *mut ffi::PyObject)
-> PyResult<Py<'p, T>>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Py::cast_from_owned_ptr(py, ptr).map_err(|e| e.into())
}
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub unsafe fn cast_from_owned_ptr_or_panic(py: Python<'p>,
@ -344,16 +382,6 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
}
}
pub fn cast_from_owned_nullptr(py: Python<'p>, ptr: *mut ffi::PyObject)
-> PyResult<Py<'p, T>>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Py::cast_from_owned_ptr(py, ptr).map_err(|e| e.into())
}
}
#[inline]
pub fn as_ref(&self) -> &T {
let offset = <T as PyTypeInfo>::offset();
@ -436,7 +464,7 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
#[inline]
pub fn extract<D>(&'p self) -> PyResult<D> where D: ::conversion::FromPyObject<'p>
{
::conversion::FromPyObject::extract(&self)
::conversion::FromPyObject::extract(&self.as_pyobject())
}
}
@ -522,8 +550,8 @@ impl<'source, T> ::FromPyObject<'source> for &'source T
where T: PyTypeInfo
{
#[inline]
default fn extract<S>(py: &'source Py<'source, S>) -> PyResult<&'source T>
where S: PyTypeInfo
default fn extract(py: &'source PyObject<'source>) -> PyResult<&'source T>
//where S: PyTypeInfo
{
Ok(py.cast_as()?)
}
@ -532,12 +560,13 @@ impl<'source, T> ::FromPyObject<'source> for &'source T
impl<'source, T> ::FromPyObject<'source> for Py<'source, T> where T: PyTypeInfo
{
#[inline]
default fn extract<S>(py: &'source Py<'source, S>) -> PyResult<Py<'source, T>>
where S: PyTypeInfo
default fn extract(py: &'source PyObject<'source>) -> PyResult<Py<'source, T>>
// where S: PyTypeInfo
{
let checked = unsafe { ffi::PyObject_TypeCheck(py.inner, T::type_object()) != 0 };
let ptr = py.as_ptr();
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 };
if checked {
Ok( unsafe { Py::<T>::from_borrowed_ptr(py.token(), py.as_ptr()) })
Ok( unsafe { Py::<T>::from_borrowed_ptr(py.token(), ptr) })
} else {
Err(PyDowncastError(py.token(), None).into())
}
@ -547,7 +576,7 @@ impl<'source, T> ::FromPyObject<'source> for Py<'source, T> where T: PyTypeInfo
impl <'a, T> ToPyObject for Py<'a, T> {
#[inline]
default fn to_object<'p>(&self, _py: Python) -> PyPtr<PyObject> {
default fn to_object<'p>(&self, _py: Python) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_borrowed_ptr(self.inner) }
}
@ -562,7 +591,7 @@ impl <'a, T> ToPyObject for Py<'a, T> {
impl<T> ToPyObject for PyPtr<T> {
#[inline]
default fn to_object(&self, _py: Python) -> PyPtr<PyObject> {
default fn to_object(&self, _py: Python) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_borrowed_ptr(self.inner) }
}
@ -577,7 +606,7 @@ impl<T> ToPyObject for PyPtr<T> {
impl<'p, T> IntoPyObject for Py<'p, T> {
#[inline]
default fn into_object(self, _py: Python) -> PyPtr<PyObject> {
default fn into_object(self, _py: Python) -> PyPtr<PyObjectMarker> {
let ptr = unsafe { PyPtr::from_owned_ptr(self.inner) };
std::mem::forget(self);
ptr

View file

@ -9,8 +9,9 @@ use std::os::raw::c_int;
use ffi;
use typeob::{PyTypeInfo, PyTypeObject, PyObjectAlloc};
use token::{PyObjectMarker, PythonToken, PythonObjectWithToken};
use objects::{PyObject, PyType, PyBool, PyDict, PyModule};
use err::{PyErr, PyResult};
use err::{PyErr, PyResult, PyDowncastError};
use pyptr::{Py, PyPtr};
use pythonrun::GILGuard;
@ -28,19 +29,18 @@ use pythonrun::GILGuard;
#[derive(Copy, Clone)]
pub struct Python<'p>(PhantomData<&'p GILGuard>);
pub struct PythonToken<T>(PhantomData<T>);
impl<T> PythonToken<T> {
pub fn token<'p>(&'p self) -> Python<'p> {
Python(PhantomData)
}
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PythonObjectWithCheckedDowncast<'p> : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_from(Py<'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)
-> Result<Self, PyDowncastError<'p>>;
}
pub trait PythonObjectWithToken : Sized {
fn token<'p>(&'p self) -> Python<'p>;
}
pub trait PyClone : Sized {
fn clone_ref(&self) -> PyPtr<Self>;
}
@ -153,7 +153,7 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`.
pub fn eval(self, code: &str, globals: Option<&PyDict>,
locals: Option<&PyDict>) -> PyResult<PyPtr<PyObject>> {
locals: Option<&PyDict>) -> PyResult<PyObject<'p>> {
self.run_code(code, ffi::Py_eval_input, globals, locals)
}
@ -174,7 +174,7 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`.
fn run_code(self, code: &str, start: c_int,
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<PyPtr<PyObject>> {
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<PyObject<'p>> {
let code = CString::new(code).unwrap();
unsafe {
@ -198,7 +198,7 @@ impl<'p> Python<'p> {
let res_ptr = ffi::PyRun_StringFlags(code.as_ptr(),
start, globals, locals, 0 as *mut _);
PyPtr::from_owned_ptr_or_err(self, res_ptr)
PyObject::from_owned_ptr_or_err(self, res_ptr)
}
}
@ -208,7 +208,7 @@ impl<'p> Python<'p> {
}
/// Import the Python module with the specified name.
pub fn import(self, name : &str) -> PyResult<Py<'p, PyModule>> {
pub fn import(self, name : &str) -> PyResult<PyModule<'p>> {
PyModule::import(self, name)
}
@ -216,39 +216,34 @@ impl<'p> Python<'p> {
where F: FnOnce(PythonToken<T>) -> T,
T: PyTypeInfo + PyObjectAlloc<Type=T>
{
let value = f(PythonToken(PhantomData));
if let Ok(ob) = Py::new(self, value) {
ob
} else {
::err::panic_after_error()
}
::token::with_token(self, f)
}
/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn None(self) -> PyPtr<PyObject> {
pub fn None(self) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_None()) }
}
/// Gets the Python builtin value `True`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn True(self) -> PyPtr<PyBool> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_True()) }
pub fn True(self) -> PyBool<'p> {
PyBool::get(self, true)
}
/// Gets the Python builtin value `False`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn False(self) -> PyPtr<PyBool> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_False()) }
pub fn False(self) -> PyBool<'p> {
PyBool::get(self, false)
}
/// Gets the Python builtin value `NotImplemented`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn NotImplemented(self) -> PyPtr<PyObject> {
pub fn NotImplemented(self) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_NotImplemented()) }
}

96
src/token.rs Normal file
View file

@ -0,0 +1,96 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std::fmt;
use std::marker::PhantomData;
use ffi;
use pyptr::{Py, PyPtr};
use err::{PyResult};
use python::{Python, ToPythonPointer, PythonObjectWithCheckedDowncast};
use objects::PyString;
use typeob::{PyTypeInfo, PyObjectAlloc};
pub struct PythonToken<T>(PhantomData<T>);
impl<T> PythonToken<T> {
pub fn token<'p>(&'p self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}
}
#[inline]
pub fn with_token<'p, T, F>(py: Python<'p>, f: F) -> Py<'p, T>
where F: FnOnce(PythonToken<T>) -> T,
T: PyTypeInfo + PyObjectAlloc<Type=T>
{
let value = f(PythonToken(PhantomData));
if let Ok(ob) = Py::new(py, value) {
ob
} else {
::err::panic_after_error()
}
}
pub trait PythonObjectWithToken : Sized {
fn token<'p>(&'p self) -> Python<'p>;
}
pub struct PyObjectMarker;
//pyobject_newtype!(PyObject, PyObject_Check, PyBaseObject_Type);
impl PyObjectMarker {
#[inline]
pub fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_owned_ptr(ptr) }
}
#[inline]
pub fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject)
-> PyResult<PyPtr<PyObjectMarker>> {
unsafe { PyPtr::from_owned_ptr_or_err(py, ptr) }
}
#[inline]
pub fn from_owned_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject)
-> Option<PyPtr<PyObjectMarker>> {
unsafe { PyPtr::from_owned_ptr_or_opt(py, ptr) }
}
#[inline]
pub fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyPtr<PyObjectMarker> {
unsafe { PyPtr::from_borrowed_ptr(ptr) }
}
}
impl<'p> fmt::Debug for PyPtr<PyObjectMarker> {
default fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
let gil = Python::acquire_gil();
let py = gil.python();
let repr_obj = unsafe {
PyString::downcast_from_owned_ptr(py, ffi::PyObject_Repr(self.as_ptr()))
.map_err(|_| fmt::Error)?
};
f.write_str(&repr_obj.to_string_lossy())
}
}
impl<'p> fmt::Display for PyPtr<PyObjectMarker> {
default fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
let gil = Python::acquire_gil();
let py = gil.python();
let str_obj = unsafe {
PyString::downcast_from_owned_ptr(py, ffi::PyObject_Str(self.as_ptr()))
.map_err(|_| fmt::Error)?
};
f.write_str(&str_obj.to_string_lossy())
}
}

View file

@ -35,6 +35,12 @@ pub trait PyTypeInfo {
}
pub trait PyObjectCtor : PyTypeInfo {
unsafe fn from_ptr(ptr: *mut ffi::PyObject) -> Self;
}
impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
type Type = T::Type;