introduce python token system

This commit is contained in:
Nikolay Kim 2017-05-27 22:45:48 -07:00
parent bfb01f65d3
commit 6c87c9b77b
36 changed files with 708 additions and 567 deletions

View file

@ -6,15 +6,33 @@ use quote::Tokens;
pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
let base = syn::Ident::from("_pyo3::PyObject"); let base = syn::Ident::from("_pyo3::PyObject");
let mut token: Option<syn::Ident> = None;
match ast.body { match ast.body {
syn::Body::Struct(syn::VariantData::Struct(_)) => { syn::Body::Struct(syn::VariantData::Struct(ref mut fields)) => {
for field in fields.iter_mut() {
let mut attrs = vec![];
for attr in field.attrs.iter() {
match attr.value {
syn::MetaItem::Word(ref a) => {
if a.as_ref() == "token" {
token = field.ident.clone();
continue
}
},
_ => (),
}
attrs.push(attr.clone());
println!("FIELD: {:?}", attr);
}
field.attrs = attrs;
}
}, },
_ => panic!("#[class] can only be used with notmal structs"), _ => panic!("#[class] can only be used with notmal structs"),
} }
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident)); let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident));
let tokens = impl_class(&ast.ident, &base); let tokens = impl_class(&ast.ident, &base, token);
quote! { quote! {
#[feature(specialization)] #[feature(specialization)]
@ -23,16 +41,54 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
const #dummy_const: () = { const #dummy_const: () = {
extern crate pyo3 as _pyo3; extern crate pyo3 as _pyo3;
use std; use std;
use pyo3::python::PythonObjectWithToken;
#tokens #tokens
}; };
} }
} }
fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens { fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) -> Tokens {
let token_name = syn::Ident::from("__py_token");
let cls_name = quote! { #cls }.as_str().to_string(); let cls_name = quote! { #cls }.as_str().to_string();
let extra = if let Some(token) = token {
Some(quote! {
impl _pyo3::python::PythonObjectWithToken for #cls {
fn token<'p>(&'p self) -> _pyo3::python::Token<'p> {
self.#token.token()
}
}
/*impl std::fmt::Debug for #cls {
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.token().with(|py| {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let repr = unsafe {
_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
py, _pyo3::ffi::PyObject_Repr(ptr))
.map_err(|_| std::fmt::Error)? };
f.write_str(&repr.to_string_lossy())
})
}
}
impl std::fmt::Display for #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.token().with(|py| {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let s = unsafe {
_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
py, _pyo3::ffi::PyObject_Str(ptr)
).map_err(|_| std::fmt::Error)?};
f.write_str(&s.to_string_lossy())
})
}
}*/
})
} else {
None
};
quote! { quote! {
impl _pyo3::typeob::PyTypeInfo for #cls { impl _pyo3::typeob::PyTypeInfo for #cls {
type Type = #cls; type Type = #cls;
@ -61,49 +117,6 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens {
} }
} }
impl _pyo3::python::ToPythonPointer for #cls { #extra
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut _pyo3::ffi::PyObject
}
}
}
impl _pyo3::python::PyClone for #cls {
fn clone_ref(&self) -> PyPtr<#cls> {
unsafe {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
_pyo3::PyPtr::from_borrowed_ptr(ptr)
}
}
}
impl std::fmt::Debug for #cls {
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
unsafe {
let py = _pyo3::Python::assume_gil_acquired();
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let repr = try!(_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
py, _pyo3::ffi::PyObject_Repr(ptr)).map_err(|_| std::fmt::Error));
f.write_str(&repr.to_string_lossy())
}
}
}
impl std::fmt::Display for #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
unsafe {
let py = _pyo3::Python::assume_gil_acquired();
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let s = try!(_pyo3::Py::<_pyo3::PyString>::cast_from_owned_nullptr(
py, _pyo3::ffi::PyObject_Str(ptr)).map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
}
} }
} }

View file

@ -48,9 +48,10 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens
{ {
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
_pyo3::callback::cb_meth(LOCATION, |py| { _pyo3::callback::cb_meth(LOCATION, |py| {
let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf); let mut slf: Py<#cls> = Py::from_borrowed_ptr(py.token(), slf);
let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py.token(), args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs); _pyo3::argparse::get_kwargs(py, kwargs);
@ -77,9 +78,10 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
{ {
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
_pyo3::callback::cb_meth(LOCATION, |py| { _pyo3::callback::cb_meth(LOCATION, |py| {
let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf); let mut slf: Py<#cls> = Py::from_borrowed_ptr(py.token(), slf);
let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py.token(), args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs); _pyo3::argparse::get_kwargs(py, kwargs);
@ -109,8 +111,9 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
_pyo3::callback::cb_meth(LOCATION, |py| { _pyo3::callback::cb_meth(LOCATION, |py| {
let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr( let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr(
py, cls as *mut _pyo3::ffi::PyObject); py.token(), cls as *mut _pyo3::ffi::PyObject);
let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let args: _pyo3::Py<_pyo3::PyTuple> =
_pyo3::Py::from_borrowed_ptr(py.token(), args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs); _pyo3::argparse::get_kwargs(py, kwargs);
@ -158,8 +161,8 @@ fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tok
const LOCATION: &'static str = concat!( const LOCATION: &'static str = concat!(
stringify!(#cls), ".setter", stringify!(#name), "()"); stringify!(#cls), ".setter", stringify!(#name), "()");
_pyo3::callback::cb_setter(LOCATION, |py| { _pyo3::callback::cb_setter(LOCATION, |py| {
let mut slf = _pyo3::Py::<#cls>::from_borrowed_ptr(py, slf); let mut slf = _pyo3::Py::<#cls>::from_borrowed_ptr(py.token(), slf);
let value = _pyo3::PyObject::from_borrowed_ptr(py, value); let value = _pyo3::PyObject::from_borrowed_ptr(py.token(), value);
let result = match <#val_ty as _pyo3::FromPyObject>::extract(&value) { let result = match <#val_ty as _pyo3::FromPyObject>::extract(&value) {
Ok(val) => slf.#name(py, val), Ok(val) => slf.#name(py, val),

View file

@ -21,9 +21,9 @@
use ffi; use ffi;
use pyptr::{Py}; use pyptr::{Py};
use python::Python; use python::{Python, PythonObjectWithToken};
use objects::{PyObject, PyTuple, PyDict, PyString, exc}; use objects::{PyObject, PyTuple, PyDict, PyString, exc};
//use conversion::RefFromPyObject; use conversion::RefFromPyObject;
use err::{self, PyResult}; use err::{self, PyResult};
/// Description of a python parameter; used for `parse_args()`. /// Description of a python parameter; used for `parse_args()`.
@ -44,17 +44,17 @@ pub struct ParamDescription<'a> {
/// Must have same length as `params` and must be initialized to `None`. /// Must have same length as `params` and must be initialized to `None`.
pub fn parse_args<'p>(py: Python<'p>, pub fn parse_args<'p>(py: Python<'p>,
fname: Option<&str>, params: &[ParamDescription], fname: Option<&str>, params: &[ParamDescription],
args: &Py<'p, PyTuple>, kwargs: Option<&'p Py<'p, PyDict>>, args: &'p PyTuple, kwargs: Option<&'p PyDict>,
accept_args: bool, accept_kwargs: bool, accept_args: bool, accept_kwargs: bool,
output: &mut[Option<Py<'p, PyObject>>]) -> PyResult<()> output: &mut[Option<&'p PyObject>]) -> PyResult<()>
{ {
assert!(params.len() == output.len()); assert!(params.len() == output.len());
let nargs = args.len()?; let nargs = args.len();
let nkeywords = kwargs.map_or(0, |d| d.len().unwrap_or(0)); let nkeywords = kwargs.map_or(0, |d| d.len());
if !accept_args && (nargs + nkeywords > params.len()) { if !accept_args && (nargs + nkeywords > params.len()) {
return Err(err::PyErr::new::<exc::TypeError, _>( return Err(err::PyErr::new::<exc::TypeError, _>(
py, py.token(),
format!("{}{} takes at most {} argument{} ({} given)", format!("{}{} takes at most {} argument{} ({} given)",
fname.unwrap_or("function"), fname.unwrap_or("function"),
if fname.is_some() { "()" } else { "" }, if fname.is_some() { "()" } else { "" },
@ -66,24 +66,26 @@ pub fn parse_args<'p>(py: Python<'p>,
let mut used_keywords = 0; let mut used_keywords = 0;
// Iterate through the parameters and assign values to output: // Iterate through the parameters and assign values to output:
for (i, (p, out)) in params.iter().zip(output).enumerate() { for (i, (p, out)) in params.iter().zip(output).enumerate() {
match kwargs.and_then(|d| d.as_ref().get_item(p.name)) { match kwargs.and_then(|d| d.get_item(p.name)) {
Some(kwarg) => { Some(kwarg) => {
*out = Some(kwarg); *out = Some(kwarg);
used_keywords += 1; used_keywords += 1;
if i < nargs { if i < nargs {
return Err(err::PyErr::new::<exc::TypeError, _>(py, return Err(err::PyErr::new::<exc::TypeError, _>(
py.token(),
format!("Argument given by name ('{}') and position ({})", format!("Argument given by name ('{}') and position ({})",
p.name, i+1))); p.name, i+1)));
} }
}, },
None => { None => {
if i < nargs { if i < nargs {
*out = Some(args.as_ref().get_item(i)); *out = Some(args.get_item(i));
} else { } else {
*out = None; *out = None;
if !p.is_optional { if !p.is_optional {
return Err(err::PyErr::new::<exc::TypeError, _>( return Err(err::PyErr::new::<exc::TypeError, _>(
py, format!("Required argument ('{}') (pos {}) not found", py.token(),
format!("Required argument ('{}') (pos {}) not found",
p.name, i+1))); p.name, i+1)));
} }
} }
@ -95,7 +97,8 @@ pub fn parse_args<'p>(py: Python<'p>,
for (key, _value) in kwargs.unwrap().items() { for (key, _value) in kwargs.unwrap().items() {
let key = try!(try!(key.cast_as::<PyString>()).to_string()); let key = try!(try!(key.cast_as::<PyString>()).to_string());
if !params.iter().any(|p| p.name == key) { if !params.iter().any(|p| p.name == key) {
return Err(err::PyErr::new::<exc::TypeError, _>(py, return Err(err::PyErr::new::<exc::TypeError, _>(
py.token(),
format!("'{}' is an invalid keyword argument for this function", format!("'{}' is an invalid keyword argument for this function",
key))); key)));
} }
@ -103,7 +106,7 @@ pub fn parse_args<'p>(py: Python<'p>,
} }
Ok(()) Ok(())
} }
/*
/// This macro is used to parse a parameter list into a set of variables. /// This macro is used to parse a parameter list into a set of variables.
/// ///
/// Syntax: `py_argparse!(py, fname, args, kwargs, (parameter-list) { body })` /// Syntax: `py_argparse!(py, fname, args, kwargs, (parameter-list) { body })`
@ -335,7 +338,7 @@ macro_rules! py_argparse_impl {
Err(e) => Err(e) Err(e) => Err(e)
} }
}}; }};
}*/ }
// Like py_argparse_impl!(), but accepts `*mut ffi::PyObject` for $args and $kwargs. // Like py_argparse_impl!(), but accepts `*mut ffi::PyObject` for $args and $kwargs.
#[macro_export] #[macro_export]
@ -357,7 +360,7 @@ pub unsafe fn get_kwargs<'p>(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(Py::<PyDict>::from_borrowed_ptr(py, ptr)) Some(Py::<PyDict>::from_borrowed_ptr(py.token(), ptr))
} }
} }

View file

@ -143,7 +143,7 @@ impl PyBuffer {
unsafe { unsafe {
let mut buf = Box::new(mem::zeroed::<ffi::Py_buffer>()); let mut buf = Box::new(mem::zeroed::<ffi::Py_buffer>());
err::error_on_minusone( err::error_on_minusone(
obj.py(), obj.token(),
ffi::PyObject_GetBuffer(obj.as_ptr(), &mut *buf, ffi::PyBUF_FULL_RO))?; ffi::PyObject_GetBuffer(obj.as_ptr(), &mut *buf, ffi::PyBUF_FULL_RO))?;
validate(&buf); validate(&buf);
Ok(PyBuffer(buf)) Ok(PyBuffer(buf))
@ -401,7 +401,7 @@ impl PyBuffer {
return incompatible_format_error(py); return incompatible_format_error(py);
} }
unsafe { unsafe {
err::error_on_minusone(py, ffi::PyBuffer_ToContiguous( err::error_on_minusone(py.token(), ffi::PyBuffer_ToContiguous(
target.as_ptr() as *mut raw::c_void, target.as_ptr() as *mut raw::c_void,
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer, &*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
self.0.len, self.0.len,
@ -436,7 +436,7 @@ impl PyBuffer {
unsafe { unsafe {
// Copy the buffer into the uninitialized space in the vector. // Copy the buffer into the uninitialized space in the vector.
// Due to T:Copy, we don't need to be concerned with Drop impls. // Due to T:Copy, we don't need to be concerned with Drop impls.
err::error_on_minusone(py, ffi::PyBuffer_ToContiguous( err::error_on_minusone(py.token(), ffi::PyBuffer_ToContiguous(
vec.as_mut_ptr() as *mut raw::c_void, vec.as_mut_ptr() as *mut raw::c_void,
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer, &*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
self.0.len, self.0.len,
@ -487,7 +487,7 @@ impl PyBuffer {
return incompatible_format_error(py); return incompatible_format_error(py);
} }
unsafe { unsafe {
err::error_on_minusone(py, ffi::PyBuffer_FromContiguous( err::error_on_minusone(py.token(), ffi::PyBuffer_FromContiguous(
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer, &*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
source.as_ptr() as *mut raw::c_void, source.as_ptr() as *mut raw::c_void,
self.0.len, self.0.len,
@ -498,15 +498,18 @@ impl PyBuffer {
} }
fn slice_length_error(py: Python) -> PyResult<()> { fn slice_length_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(py, "Slice length does not match buffer length.")) Err(err::PyErr::new::<exc::BufferError, _>(
py.token(), "Slice length does not match buffer length."))
} }
fn incompatible_format_error(py: Python) -> PyResult<()> { fn incompatible_format_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(py, "Slice type is incompatible with buffer format.")) Err(err::PyErr::new::<exc::BufferError, _>(
py.token(), "Slice type is incompatible with buffer format."))
} }
fn buffer_readonly_error(py: Python) -> PyResult<()> { fn buffer_readonly_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(py, "Cannot write to read-only buffer.")) Err(err::PyErr::new::<exc::BufferError, _>(
py.token(), "Cannot write to read-only buffer."))
} }
impl Drop for PyBuffer { impl Drop for PyBuffer {

View file

@ -5,7 +5,7 @@ use std::{any, mem, ptr, isize, io, panic};
use libc; use libc;
use pyptr::Py; use pyptr::Py;
use python::{Python, IntoPythonPointer}; use python::{Python, IntoPythonPointer, PythonObjectWithToken};
use objects::exc; use objects::exc;
use conversion::IntoPyObject; use conversion::IntoPyObject;
use ffi::{self, Py_hash_t}; use ffi::{self, Py_hash_t};
@ -27,7 +27,7 @@ impl<S> CallbackConverter<S> for PyObjectCallbackConverter
type R = *mut ffi::PyObject; type R = *mut ffi::PyObject;
fn convert(val: S, py: Python) -> *mut ffi::PyObject { fn convert(val: S, py: Python) -> *mut ffi::PyObject {
val.into_object(py).into_ptr() val.into_object(py.token()).into_ptr()
} }
#[inline] #[inline]
@ -62,7 +62,8 @@ impl CallbackConverter<usize> for LenResultConverter {
if val <= (isize::MAX as usize) { if val <= (isize::MAX as usize) {
val as isize val as isize
} else { } else {
PyErr::new_lazy_init(py.get_ptype::<exc::OverflowError>(), None).restore(py); PyErr::new_lazy_init(
py.get_type::<exc::OverflowError>(), None).restore(py.token());
-1 -1
} }
} }
@ -176,7 +177,7 @@ pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
C::convert(val, py) C::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
C::error_value() C::error_value()
} }
} }
@ -203,14 +204,14 @@ pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
let guard = AbortOnDrop(location); let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| { let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let mut slf: Py<Slf> = Py::from_borrowed_ptr(py, slf); let mut slf: Py<Slf> = Py::from_borrowed_ptr(py.token(), slf);
match f(py, slf.as_mut()) { match f(py, slf.as_mut()) {
Ok(val) => { Ok(val) => {
C::convert(val, py) C::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
C::error_value() C::error_value()
} }
} }
@ -235,7 +236,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
let guard = AbortOnDrop(location); let guard = AbortOnDrop(location);
let ret = panic::catch_unwind(|| { let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let mut slf: Py<Slf> = Py::from_borrowed_ptr(py, slf); let mut slf: Py<Slf> = Py::from_borrowed_ptr(py.token(), slf);
f(py, slf.as_mut()) f(py, slf.as_mut())
}); });
@ -297,7 +298,7 @@ pub unsafe fn cb_convert<C, T>(_c: C, py: Python, value: PyResult<T>) -> C::R
match value { match value {
Ok(val) => C::convert(val, py), Ok(val) => C::convert(val, py),
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
C::error_value() C::error_value()
} }
} }

View file

@ -8,7 +8,7 @@
use ffi; use ffi;
use err::PyResult; use err::PyResult;
use python::Python; use python::{Python, PythonObjectWithToken};
use callback::PyObjectCallbackConverter; use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use class::methods::PyMethodDef; use class::methods::PyMethodDef;

View file

@ -11,7 +11,7 @@ use std::os::raw::c_int;
use ::{Py, CompareOp}; use ::{Py, CompareOp};
use ffi; use ffi;
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use python::{Python, IntoPythonPointer}; use python::{Python, IntoPythonPointer, PythonObjectWithToken};
use objects::{exc, PyObject}; use objects::{exc, PyObject};
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use conversion::{ToPyObject, FromPyObject, IntoPyObject}; use conversion::{ToPyObject, FromPyObject, IntoPyObject};
@ -345,8 +345,8 @@ impl<T> PyObjectRichcmpProtocolImpl for T where T: for<'p> PyObjectRichcmpProtoc
let guard = ::callback::AbortOnDrop(LOCATION); let guard = ::callback::AbortOnDrop(LOCATION);
let ret = std::panic::catch_unwind(|| { let ret = std::panic::catch_unwind(|| {
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let slf = Py::<T>::from_borrowed_ptr(py, slf); let slf = Py::<T>::from_borrowed_ptr(py.token(), slf);
let arg = PyObject::from_borrowed_ptr(py, arg); let arg = PyObject::from_borrowed_ptr(py.token(), arg);
let res = match extract_op(py, op) { let res = match extract_op(py, op) {
Ok(op) => { Ok(op) => {
@ -361,10 +361,10 @@ impl<T> PyObjectRichcmpProtocolImpl for T where T: for<'p> PyObjectRichcmpProtoc
}; };
match res { match res {
Ok(val) => { Ok(val) => {
val.into_object(py).into_ptr() val.into_object(py.token()).into_ptr()
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
std::ptr::null_mut() std::ptr::null_mut()
} }
} }
@ -394,8 +394,8 @@ fn extract_op(py: Python, op: c_int) -> PyResult<CompareOp> {
ffi::Py_GT => Ok(CompareOp::Gt), ffi::Py_GT => Ok(CompareOp::Gt),
ffi::Py_GE => Ok(CompareOp::Ge), ffi::Py_GE => Ok(CompareOp::Ge),
_ => Err(PyErr::new_lazy_init( _ => Err(PyErr::new_lazy_init(
py.get_ptype::<exc::ValueError>(), py.get_type::<exc::ValueError>(),
Some("tp_richcompare called with invalid comparison operator" Some("tp_richcompare called with invalid comparison operator"
.to_object(py).into_pptr()))) .to_object(py.token()))))
} }
} }

View file

@ -9,7 +9,7 @@ use std::os::raw::c_int;
use ffi; use ffi;
use err::PyResult; use err::PyResult;
use python::Python; use python::{Python, PythonObjectWithToken};
use objects::PyObject; use objects::PyObject;
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use callback::{handle, UnitCallbackConverter}; use callback::{handle, UnitCallbackConverter};
@ -73,7 +73,7 @@ impl ffi::PyBufferProcs {
{ {
const LOCATION: &'static str = concat!(stringify!(T), ".buffer_get::<PyBufferProtocol>()"); const LOCATION: &'static str = concat!(stringify!(T), ".buffer_get::<PyBufferProtocol>()");
handle(LOCATION, UnitCallbackConverter, |py| { handle(LOCATION, UnitCallbackConverter, |py| {
let slf = PyObject::from_borrowed_ptr(py, slf); let slf = PyObject::from_borrowed_ptr(py.token(), slf);
slf.bf_getbuffer(py, arg1, arg2) slf.bf_getbuffer(py, arg1, arg2)
}) })
} }

View file

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

View file

@ -8,7 +8,7 @@ use std::os::raw::{c_int, c_void};
use ffi; use ffi;
use pyptr::Py; use pyptr::Py;
use python::{Python, ToPythonPointer}; use python::{Python, ToPythonPointer, PythonObjectWithToken};
use callback::AbortOnDrop; use callback::AbortOnDrop;
use class::NO_METHODS; use class::NO_METHODS;
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
@ -90,7 +90,7 @@ unsafe extern "C" fn tp_traverse<T>(slf: *mut ffi::PyObject,
let guard = AbortOnDrop(LOCATION); let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let visit = PyVisit { visit: visit, arg: arg, _py: py }; let visit = PyVisit { visit: visit, arg: arg, _py: py };
let slf: Py<T> = Py::from_borrowed_ptr(py, slf); let slf: Py<T> = Py::from_borrowed_ptr(py.token(), slf);
let ret = match T::__traverse__(&slf, py, visit) { let ret = match T::__traverse__(&slf, py, visit) {
Ok(()) => 0, Ok(()) => 0,
@ -107,7 +107,7 @@ unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
let guard = AbortOnDrop(LOCATION); let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let slf: Py<T> = Py::from_borrowed_ptr(py, slf); let slf: Py<T> = Py::from_borrowed_ptr(py.token(), slf);
T::__clear__(slf.as_mut(), py); T::__clear__(slf.as_mut(), py);
mem::forget(guard); mem::forget(guard);
0 0

View file

@ -8,7 +8,7 @@
use ffi; use ffi;
use err::PyResult; use err::PyResult;
use python::Python; use python::{Python, PythonObjectWithToken};
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use callback::PyObjectCallbackConverter; use callback::PyObjectCallbackConverter;

View file

@ -16,7 +16,7 @@ macro_rules! py_unary_func {
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let res = slf.as_mut().$f(py).into(); let res = slf.as_mut().$f(py).into();
match res { match res {
@ -25,7 +25,7 @@ macro_rules! py_unary_func {
::convert(val, py) ::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
::error_value() ::error_value()
} }
@ -60,7 +60,7 @@ macro_rules! py_unary_func_self {
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let res = slf.$f(py).into(); let res = slf.$f(py).into();
match res { match res {
@ -69,7 +69,7 @@ macro_rules! py_unary_func_self {
::convert(val, py) ::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
::error_value() ::error_value()
} }
@ -126,8 +126,8 @@ macro_rules! py_binary_func{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let arg = $crate::PyObject::from_borrowed_ptr(py, arg); let arg = $crate::PyObject::from_borrowed_ptr(py.token(), arg);
let result = match arg.extract() { let result = match arg.extract() {
Ok(arg) => { Ok(arg) => {
@ -142,7 +142,7 @@ macro_rules! py_binary_func{
::convert(val, py) ::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
::error_value() ::error_value()
} }
@ -178,8 +178,8 @@ macro_rules! py_binary_self_func{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf1 = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf1 = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let arg = $crate::PyObject::from_borrowed_ptr(py, arg); let arg = $crate::PyObject::from_borrowed_ptr(py.token(), arg);
let result = match arg.extract() { let result = match arg.extract() {
Ok(arg) => { Ok(arg) => {
@ -193,7 +193,7 @@ macro_rules! py_binary_self_func{
slf slf
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
$crate::std::ptr::null_mut() $crate::std::ptr::null_mut()
} }
} }
@ -228,7 +228,7 @@ macro_rules! py_ssizearg_func {
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let result = slf.as_mut().$f(py, arg as isize).into(); let result = slf.as_mut().$f(py, arg as isize).into();
match result { match result {
@ -237,7 +237,7 @@ macro_rules! py_ssizearg_func {
::convert(val, py) ::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
::error_value() ::error_value()
} }
@ -276,9 +276,9 @@ macro_rules! py_ternary_func{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1); let arg1 = $crate::PyObject::from_borrowed_ptr(py.token(), arg1);
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2); let arg2 = $crate::PyObject::from_borrowed_ptr(py.token(), arg2);
let result = match arg1.extract() { let result = match arg1.extract() {
Ok(arg1) => match arg2.extract() { Ok(arg1) => match arg2.extract() {
@ -294,7 +294,7 @@ macro_rules! py_ternary_func{
::convert(val, py) ::convert(val, py)
} }
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
::error_value() ::error_value()
} }
@ -333,9 +333,9 @@ macro_rules! py_ternary_self_func{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf1 = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf1 = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1); let arg1 = $crate::PyObject::from_borrowed_ptr(py.token(), arg1);
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2); let arg2 = $crate::PyObject::from_borrowed_ptr(py.token(), arg2);
let result = match arg1.extract() { let result = match arg1.extract() {
Ok(arg1) => match arg2.extract() { Ok(arg1) => match arg2.extract() {
@ -348,7 +348,7 @@ macro_rules! py_ternary_self_func{
match result { match result {
Ok(_) => slf, Ok(_) => slf,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
$crate::std::ptr::null_mut() $crate::std::ptr::null_mut()
} }
} }
@ -385,13 +385,13 @@ macro_rules! py_func_set{
$crate::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| { $crate::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
if value.is_null() { if value.is_null() {
let e = PyErr::new::<exc::NotImplementedError, _>( let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Subscript deletion not supported by {:?}", py.token(), format!("Subscript deletion not supported by {:?}",
stringify!(T))); stringify!(T)));
e.restore(py); e.restore(py.token());
return -1 return -1
} else { } else {
let name = ::PyObject::from_borrowed_ptr(py, name); let name = ::PyObject::from_borrowed_ptr(py.token(), name);
let value = ::PyObject::from_borrowed_ptr(py, value); let value = ::PyObject::from_borrowed_ptr(py.token(), value);
let result = match name.extract() { let result = match name.extract() {
Ok(name) => match value.extract() { Ok(name) => match value.extract() {
Ok(value) => { Ok(value) => {
@ -405,7 +405,7 @@ macro_rules! py_func_set{
Ok(_) => Ok(_) =>
0, 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
@ -432,10 +432,10 @@ macro_rules! py_func_del{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
if value.is_null() { if value.is_null() {
let name = PyObject::from_borrowed_ptr(py, name); let name = PyObject::from_borrowed_ptr(py.token(), name);
let result = match name.extract() { let result = match name.extract() {
Ok(name) => Ok(name) =>
slf.as_mut().$f(py, name).into(), slf.as_mut().$f(py, name).into(),
@ -445,15 +445,15 @@ macro_rules! py_func_del{
Ok(_) => Ok(_) =>
0, 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
} else { } else {
let e = PyErr::new::<exc::NotImplementedError, _>( let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Subscript assignment not supported by {:?}", py.token(), format!("Subscript assignment not supported by {:?}",
stringify!(T))); stringify!(T)));
e.restore(py); e.restore(py.token());
return -1 return -1
} }
@ -490,8 +490,8 @@ macro_rules! py_func_set_del{
let guard = $crate::callback::AbortOnDrop(LOCATION); let guard = $crate::callback::AbortOnDrop(LOCATION);
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py.token(), slf);
let name = PyObject::from_borrowed_ptr(py, name); let name = PyObject::from_borrowed_ptr(py.token(), name);
if value.is_null() { if value.is_null() {
let result = match name.extract() { let result = match name.extract() {
@ -503,12 +503,12 @@ macro_rules! py_func_set_del{
Ok(_) => Ok(_) =>
0, 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
} else { } else {
let value = ::PyObject::from_borrowed_ptr(py, value); let value = ::PyObject::from_borrowed_ptr(py.token(), value);
let result = match name.extract() { let result = match name.extract() {
Ok(name) => match value.extract() { Ok(name) => match value.extract() {
Ok(value) => { Ok(value) => {
@ -522,7 +522,7 @@ macro_rules! py_func_set_del{
Ok(_) => Ok(_) =>
0, 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }

View file

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

View file

@ -5,7 +5,7 @@
use ffi; use ffi;
use err::PyResult; use err::PyResult;
use python::Python; use python::{Python, PythonObjectWithToken};
use callback::PyObjectCallbackConverter; use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use class::methods::PyMethodDef; use class::methods::PyMethodDef;

View file

@ -6,7 +6,7 @@
use std::os::raw::c_int; use std::os::raw::c_int;
use ffi; use ffi;
use python::Python; use python::{Python, PythonObjectWithToken};
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use objects::{exc, PyObject}; use objects::{exc, PyObject};
use callback::{PyObjectCallbackConverter, LenResultConverter, BoolCallbackConverter}; use callback::{PyObjectCallbackConverter, LenResultConverter, BoolCallbackConverter};
@ -195,11 +195,12 @@ impl<T> PySequenceSetItemProtocolImpl for T where T: for<'p> PySequenceSetItemPr
::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| { ::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
if value.is_null() { if value.is_null() {
let e = PyErr::new::<exc::NotImplementedError, _>( let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Item deletion not supported by {:?}", stringify!(T))); py.token(),
e.restore(py); format!("Item deletion not supported by {:?}", stringify!(T)));
e.restore(py.token());
return -1 return -1
} else { } else {
let value = PyObject::from_borrowed_ptr(py, value); let value = PyObject::from_borrowed_ptr(py.token(), value);
let result = match value.extract() { let result = match value.extract() {
Ok(value) => { Ok(value) => {
slf.__setitem__(py, key as isize, value).into() slf.__setitem__(py, key as isize, value).into()
@ -209,7 +210,7 @@ impl<T> PySequenceSetItemProtocolImpl for T where T: for<'p> PySequenceSetItemPr
match result { match result {
Ok(_) => 0, Ok(_) => 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
@ -247,15 +248,15 @@ impl<T> PySequenceDelItemProtocolImpl for T where T: for<'p> PySequenceDelItemPr
match result { match result {
Ok(_) => 0, Ok(_) => 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
} else { } else {
let e = PyErr::new::<exc::NotImplementedError, _>( let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Item assignment not supported by {:?}", py.token(), format!("Item assignment not supported by {:?}",
stringify!(T))); stringify!(T)));
e.restore(py); e.restore(py.token());
return -1 return -1
} }
}) })
@ -281,12 +282,12 @@ impl<T> PySequenceDelItemProtocolImpl for T
match result { match result {
Ok(_) => 0, Ok(_) => 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }
} else { } else {
let value = ::PyObject::from_borrowed_ptr(py, value); let value = ::PyObject::from_borrowed_ptr(py.token(), value);
let result = match value.extract() { let result = match value.extract() {
Ok(value) => { Ok(value) => {
slf.__setitem__(py, key as isize, value).into() slf.__setitem__(py, key as isize, value).into()
@ -296,7 +297,7 @@ impl<T> PySequenceDelItemProtocolImpl for T
match result { match result {
Ok(_) => 0, Ok(_) => 0,
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
-1 -1
} }
} }

View file

@ -1,7 +1,7 @@
use ffi; use ffi;
use err::PyResult; use err::PyResult;
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer}; use python::{Python, ToPythonPointer, Token};
use objects::{PyObject, PyTuple}; use objects::{PyObject, PyTuple};
use typeob::{PyTypeInfo}; use typeob::{PyTypeInfo};
@ -10,7 +10,7 @@ use typeob::{PyTypeInfo};
pub trait ToPyObject { pub trait ToPyObject {
/// Converts self into a Python object. /// Converts self into a Python object.
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject>; fn to_object(&self, py: Token) -> PyPtr<PyObject>;
/// Converts self into a Python object and calls the specified closure /// Converts self into a Python object and calls the specified closure
/// on the native FFI pointer underlying the Python object. /// on the native FFI pointer underlying the Python object.
@ -18,7 +18,7 @@ pub trait ToPyObject {
/// May be more efficient than `to_py_object` because it does not need /// May be more efficient than `to_py_object` because it does not need
/// to touch any reference counts when the input object already is a Python object. /// to touch any reference counts when the input object already is a Python object.
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R fn with_borrowed_ptr<F, R>(&self, py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R where F: FnOnce(*mut ffi::PyObject) -> R
{ {
let obj = self.to_object(py).into_object(); let obj = self.to_object(py).into_object();
@ -30,7 +30,7 @@ pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self) /// Converts self into a Python object. (Consumes self)
#[inline] #[inline]
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> fn into_object(self, py: Token) -> PyPtr<PyObject>
where Self: Sized; where Self: Sized;
} }
@ -39,12 +39,12 @@ pub trait IntoPyObject {
pub trait ToPyTuple { pub trait ToPyTuple {
/// Converts self into a PyTuple object. /// Converts self into a PyTuple object.
fn to_py_tuple<'p>(&self, py: Python<'p>) -> Py<'p, PyTuple>; fn to_py_tuple(&self, py: Token) -> PyPtr<PyTuple>;
/// Converts self into a PyTuple object and calls the specified closure /// Converts self into a PyTuple object and calls the specified closure
/// on the native FFI pointer underlying the Python object. /// on the native FFI pointer underlying the Python object.
#[inline] #[inline]
fn with_borrowed_ptr<'p, F, R>(&self, py: Python<'p>, f: F) -> R fn with_borrowed_ptr<F, R>(&self, py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R where F: FnOnce(*mut ffi::PyObject) -> R
{ {
let obj = self.to_py_tuple(py); let obj = self.to_py_tuple(py);
@ -102,7 +102,7 @@ impl <'p, T: ?Sized> RefFromPyObject<'p> for T
impl<T> IntoPyObject for T where T: ToPyObject impl<T> IntoPyObject for T where T: ToPyObject
{ {
#[inline] #[inline]
default fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized default fn into_object(self, py: Token) -> PyPtr<PyObject> where Self: Sized
{ {
self.to_object(py) self.to_object(py)
} }
@ -114,12 +114,12 @@ impl<T> IntoPyObject for T where T: ToPyObject
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject { impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
#[inline] #[inline]
default fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { default fn to_object(&self, py: Token) -> PyPtr<PyObject> {
<T as ToPyObject>::to_object(*self, py) <T as ToPyObject>::to_object(*self, py)
} }
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R fn with_borrowed_ptr<F, R>(&self, py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R where F: FnOnce(*mut ffi::PyObject) -> R
{ {
<T as ToPyObject>::with_borrowed_ptr(*self, py, f) <T as ToPyObject>::with_borrowed_ptr(*self, py, f)
@ -130,7 +130,7 @@ impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
/// `Option::None` is converted to Python `None`. /// `Option::None` is converted to Python `None`.
impl <T> ToPyObject for Option<T> where T: ToPyObject { impl <T> ToPyObject for Option<T> where T: ToPyObject {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
match *self { match *self {
Some(ref val) => val.to_object(py), Some(ref val) => val.to_object(py),
None => py.None() None => py.None()
@ -140,7 +140,7 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
impl<T> IntoPyObject for Option<T> where T: IntoPyObject { impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> { fn into_object(self, py: Token) -> PyPtr<PyObject> {
match self { match self {
Some(val) => val.into_object(py), Some(val) => val.into_object(py),
None => py.None() None => py.None()
@ -151,7 +151,7 @@ impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
/// `()` is converted to Python `None`. /// `()` is converted to Python `None`.
impl ToPyObject for () { impl ToPyObject for () {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
py.None() py.None()
} }
} }

View file

@ -4,7 +4,7 @@ use libc;
use ffi; use ffi;
use pyptr::{Py, PyPtr}; use pyptr::{Py, PyPtr};
use python::{ToPythonPointer, Python, IntoPythonPointer}; use python::{ToPythonPointer, Python, IntoPythonPointer, Token, PythonObjectWithToken};
use objects::{PyObject, PyType, exc}; use objects::{PyObject, PyType, exc};
use typeob::{PyTypeObject}; use typeob::{PyTypeObject};
use conversion::{ToPyObject, ToPyTuple}; use conversion::{ToPyObject, ToPyTuple};
@ -102,7 +102,7 @@ pub type PyResult<T> = Result<T, PyErr>;
// Marker type that indicates an error while downcasting // Marker type that indicates an error while downcasting
pub struct PyDowncastError<'p>(pub Python<'p>, pub Option<&'p str>); pub struct PyDowncastError<'p>(pub Token<'p>, pub Option<&'p str>);
impl PyErr { impl PyErr {
@ -117,15 +117,15 @@ impl PyErr {
/// ///
/// Example: /// Example:
/// `return Err(PyErr::new::<exc::TypeError, _>(py, "Error message"));` /// `return Err(PyErr::new::<exc::TypeError, _>(py, "Error message"));`
pub fn new<T, V>(py: Python, value: V) -> PyErr pub fn new<T, V>(py: Token, value: V) -> PyErr
where T: PyTypeObject, V: ToPyObject where T: PyTypeObject, V: ToPyObject
{ {
PyErr::new_helper(py, py.get_ptype::<T>(), value.to_object(py).into_pptr()) PyErr::new_helper(py, py.get_type::<T>(), value.to_object(py))
} }
/// Gets whether an error is present in the Python interpreter's global state. /// Gets whether an error is present in the Python interpreter's global state.
#[inline] #[inline]
pub fn occurred(_ : Python) -> bool { pub fn occurred(_ : Token) -> bool {
unsafe { !ffi::PyErr_Occurred().is_null() } unsafe { !ffi::PyErr_Occurred().is_null() }
} }
@ -157,7 +157,7 @@ impl PyErr {
/// Retrieves the current error from the Python interpreter's global state. /// Retrieves the current error from the Python interpreter's global state.
/// The error is cleared from the Python interpreter. /// The error is cleared from the Python interpreter.
/// If no error is set, returns a `SystemError`. /// If no error is set, returns a `SystemError`.
pub fn fetch(py: Python) -> PyErr { pub fn fetch(py: Token) -> PyErr {
unsafe { unsafe {
let mut ptype : *mut ffi::PyObject = std::mem::uninitialized(); let mut ptype : *mut ffi::PyObject = std::mem::uninitialized();
let mut pvalue : *mut ffi::PyObject = std::mem::uninitialized(); let mut pvalue : *mut ffi::PyObject = std::mem::uninitialized();
@ -167,7 +167,7 @@ impl PyErr {
} }
} }
unsafe fn new_from_ffi_tuple(py: Python, unsafe fn new_from_ffi_tuple(py: Token,
ptype: *mut ffi::PyObject, ptype: *mut ffi::PyObject,
pvalue: *mut ffi::PyObject, pvalue: *mut ffi::PyObject,
ptraceback: *mut ffi::PyObject) -> PyErr { ptraceback: *mut ffi::PyObject) -> PyErr {
@ -175,16 +175,16 @@ impl PyErr {
// and because we mustn't panic in normalize(). // and because we mustn't panic in normalize().
PyErr { PyErr {
ptype: if ptype.is_null() { ptype: if ptype.is_null() {
py.get_ptype::<exc::SystemError>() py.get_type::<exc::SystemError>()
} else { } else {
Py::<PyType>::from_borrowed_ptr(py, ptype).into_pptr() PyPtr::from_borrowed_ptr(ptype)
}, },
pvalue: PyObject::from_borrowed_pptr_opt(py, pvalue), pvalue: PyPtr::from_borrowed_ptr_opt(py, pvalue),
ptraceback: PyObject::from_borrowed_pptr_opt(py, ptraceback) ptraceback: PyPtr::from_borrowed_ptr_opt(py, ptraceback)
} }
} }
fn new_helper(_py: Python, ty: PyPtr<PyType>, value: PyPtr<PyObject>) -> PyErr { fn new_helper(_py: Token, ty: PyPtr<PyType>, value: PyPtr<PyObject>) -> PyErr {
assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0); assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0);
PyErr { PyErr {
ptype: ty, ptype: ty,
@ -198,28 +198,28 @@ impl PyErr {
/// `obj` must be an Python exception instance, the PyErr will use that instance. /// `obj` must be an Python exception instance, the PyErr will use that instance.
/// If `obj` is a Python exception type object, the PyErr will (lazily) create a new instance of that type. /// If `obj` is a Python exception type object, the PyErr will (lazily) create a new instance of that type.
/// Otherwise, a `TypeError` is created instead. /// Otherwise, a `TypeError` is created instead.
pub fn from_instance<O>(py: Python, obj: O) -> PyErr where O: ToPyObject { pub fn from_instance<O>(py: Token, obj: O) -> PyErr where O: ToPyObject {
PyErr::from_instance_helper(py, obj.to_object(py)) PyErr::from_instance_helper(py, obj.to_object(py))
} }
fn from_instance_helper<'p>(py: Python<'p>, obj: Py<'p, PyObject>) -> PyErr { fn from_instance_helper<'p>(py: Token, obj: PyPtr<PyObject>) -> PyErr {
if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 { if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 {
PyErr { PyErr {
ptype: unsafe { Py::<PyType>::from_borrowed_ptr( ptype: unsafe { PyPtr::<PyType>::from_borrowed_ptr(
py, ffi::PyExceptionInstance_Class(obj.as_ptr())).into_pptr() }, ffi::PyExceptionInstance_Class(obj.as_ptr())) },
pvalue: Some(obj.into_pptr()), pvalue: Some(obj),
ptraceback: None ptraceback: None
} }
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 { } else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr { PyErr {
ptype: unsafe { Py::<PyType>::unchecked_downcast_from(obj).into_pptr() }, ptype: unsafe { PyPtr::<PyType>::unchecked_downcast_from(obj) },
pvalue: None, pvalue: None,
ptraceback: None ptraceback: None
} }
} else { } else {
PyErr { PyErr {
ptype: py.get_ptype::<exc::TypeError>(), ptype: py.get_type::<exc::TypeError>(),
pvalue: Some("exceptions must derive from BaseException".to_object(py).into_pptr()), pvalue: Some("exceptions must derive from BaseException".to_object(py)),
ptraceback: None ptraceback: None
} }
} }
@ -241,26 +241,26 @@ impl PyErr {
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`. /// `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. /// `args` is the a tuple of arguments to pass to the exception constructor.
#[inline] #[inline]
pub fn new_err<'p, A>(py: Python<'p>, exc: Py<'p, PyType>, args: A) -> PyErr pub fn new_err<'p, A>(py: Token, exc: Py<'p, PyType>, args: A) -> PyErr
where A: 'p + ToPyTuple where A: 'p + ToPyTuple
{ {
let exc = exc.clone_ref(); let exc = exc.clone_ref();
let pval = args.to_py_tuple(py); let pval = args.to_py_tuple(py);
PyErr { PyErr {
ptype: exc.into_pptr(), ptype: exc.into_pptr(),
pvalue: Some(pval.into_object().into_pptr()), pvalue: Some(pval.into_object()),
ptraceback: None ptraceback: None
} }
} }
/// Print a standard traceback to sys.stderr. /// Print a standard traceback to sys.stderr.
pub fn print(self, py: Python) { pub fn print(self, py: Token) {
self.restore(py); self.restore(py);
unsafe { ffi::PyErr_PrintEx(0) } unsafe { ffi::PyErr_PrintEx(0) }
} }
/// Print a standard traceback to sys.stderr. /// Print a standard traceback to sys.stderr.
pub fn print_and_set_sys_last_vars(self, py: Python) { pub fn print_and_set_sys_last_vars(self, py: Token) {
self.restore(py); self.restore(py);
unsafe { ffi::PyErr_PrintEx(1) } unsafe { ffi::PyErr_PrintEx(1) }
} }
@ -268,7 +268,7 @@ impl PyErr {
/// Return true if the current exception matches the exception in `exc`. /// Return true if the current exception matches the exception in `exc`.
/// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass. /// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass.
/// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match. /// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match.
pub fn matches<T>(&self, py: Python, exc: T) -> bool pub fn matches<T>(&self, py: Token, exc: T) -> bool
where T: ToPyObject where T: ToPyObject
{ {
exc.with_borrowed_ptr(py, |exc| unsafe { exc.with_borrowed_ptr(py, |exc| unsafe {
@ -277,7 +277,7 @@ impl PyErr {
} }
/// Normalizes the error. This ensures that the exception value is an instance of the exception type. /// Normalizes the error. This ensures that the exception value is an instance of the exception type.
pub fn normalize(&mut self, py: Python) { pub fn normalize(&mut self, py: Token) {
// The normalization helper function involves temporarily moving out of the &mut self, // The normalization helper function involves temporarily moving out of the &mut self,
// which requires some unsafe trickery: // which requires some unsafe trickery:
unsafe { unsafe {
@ -288,7 +288,7 @@ impl PyErr {
/// Helper function for normalizing the error by deconstructing and reconstructing the PyErr. /// Helper function for normalizing the error by deconstructing and reconstructing the PyErr.
/// Must not panic for safety in normalize() /// Must not panic for safety in normalize()
fn into_normalized(self, py: Python) -> PyErr { fn into_normalized(self, py: Token) -> PyErr {
let PyErr { ptype, pvalue, ptraceback } = self; let PyErr { ptype, pvalue, ptraceback } = self;
let mut ptype = ptype.into_ptr(); let mut ptype = ptype.into_ptr();
let mut pvalue = pvalue.into_ptr(); let mut pvalue = pvalue.into_ptr();
@ -300,25 +300,25 @@ impl PyErr {
} }
/// Retrieves the exception type. /// Retrieves the exception type.
pub fn get_type<'p>(&self, py: Python<'p>) -> Py<'p, PyType> { pub fn get_type<'p>(&self, py: Token<'p>) -> Py<'p, PyType> {
self.ptype.as_ref(py) self.ptype.as_ref(py)
} }
/// Retrieves the exception instance for this error. /// Retrieves the exception instance for this error.
/// This method takes `&mut self` because the error might need /// This method takes `&mut self` because the error might need
/// to be normalized in order to create the exception instance. /// 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: Token<'p>) -> Py<'p, PyObject> {
self.normalize(py); self.normalize(py);
match self.pvalue { match self.pvalue {
Some(ref instance) => instance.as_ref(py), Some(ref instance) => instance.as_ref(py),
None => py.None() None => py.None().as_ref(py),
} }
} }
/// Writes the error back to the Python interpreter's global state. /// Writes the error back to the Python interpreter's global state.
/// This is the opposite of `PyErr::fetch()`. /// This is the opposite of `PyErr::fetch()`.
#[inline] #[inline]
pub fn restore(self, _py: Python) { pub fn restore(self, _py: Token) {
let PyErr { ptype, pvalue, ptraceback } = self; let PyErr { ptype, pvalue, ptraceback } = self;
unsafe { unsafe {
ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr()) ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr())
@ -327,10 +327,11 @@ impl PyErr {
/// Issue a warning message. /// Issue a warning message.
/// May return a PyErr if warnings-as-errors is enabled. /// May return a PyErr if warnings-as-errors is enabled.
pub fn warn(py: Python, category: &PyObject, message: &str, stacklevel: i32) -> PyResult<()> { pub fn warn(py: Token, category: &PyObject, message: &str, stacklevel: i32) -> PyResult<()> {
let message = CString::new(message).unwrap(); let message = CString::new(message).unwrap();
unsafe { unsafe {
error_on_minusone(py, ffi::PyErr_WarnEx(category.as_ptr(), message.as_ptr(), stacklevel as ffi::Py_ssize_t)) error_on_minusone(py, ffi::PyErr_WarnEx(
category.as_ptr(), message.as_ptr(), stacklevel as ffi::Py_ssize_t))
} }
} }
} }
@ -349,7 +350,7 @@ impl PyErr {
/// Converts `PyDowncastError` to Python `TypeError`. /// Converts `PyDowncastError` to Python `TypeError`.
impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr { impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr {
fn from(err: PyDowncastError<'p>) -> PyErr { fn from(err: PyDowncastError<'p>) -> PyErr {
PyErr::new_lazy_init(err.0.get_ptype::<exc::TypeError>(), None) PyErr::new_lazy_init(err.0.get_type::<exc::TypeError>(), None)
} }
} }
@ -367,14 +368,14 @@ impl std::convert::From<PyErr> for std::io::Error {
} }
} }
pub fn panic_after_error(_py: Python) -> ! { pub fn panic_after_error() -> ! {
unsafe { ffi::PyErr_Print(); } unsafe { ffi::PyErr_Print(); }
panic!("Python API called failed"); panic!("Python API called failed");
} }
/// Returns Ok if the error code is not -1. /// Returns Ok if the error code is not -1.
#[inline] #[inline]
pub fn error_on_minusone(py: Python, result: libc::c_int) -> PyResult<()> { pub fn error_on_minusone(py: Token, result: libc::c_int) -> PyResult<()> {
if result != -1 { if result != -1 {
Ok(()) Ok(())
} else { } else {

View file

@ -141,5 +141,5 @@ macro_rules! py_fn_impl {
#[allow(dead_code)] #[allow(dead_code)]
pub unsafe fn py_fn_impl<'p>(py: Python<'p>, pub unsafe fn py_fn_impl<'p>(py: Python<'p>,
method_def: *mut ffi::PyMethodDef) -> Py<'p, PyObject> { method_def: *mut ffi::PyMethodDef) -> Py<'p, PyObject> {
Py::from_owned_ptr_or_panic(py, ffi::PyCFunction_New(method_def, ptr::null_mut())) Py::from_owned_ptr_or_panic(py.token(), ffi::PyCFunction_New(method_def, ptr::null_mut()))
} }

View file

@ -69,7 +69,7 @@ pub use pyptr::{Py, PyPtr};
pub use err::{PyErr, PyResult, PyDowncastError}; pub use err::{PyErr, PyResult, PyDowncastError};
pub use objects::*; pub use objects::*;
pub use python::{AsPy, Python, PythonToken}; pub use python::{Python, PythonToken, IntoPythonPointer, PythonObjectWithToken};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python}; pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple}; pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple};
pub use class::{CompareOp}; pub use class::{CompareOp};
@ -192,7 +192,6 @@ macro_rules! py_module_init {
} }
} }
use python::IntoPythonPointer;
#[doc(hidden)] #[doc(hidden)]
pub unsafe fn py_module_init_impl( pub unsafe fn py_module_init_impl(
@ -208,10 +207,10 @@ pub unsafe fn py_module_init_impl(
return module; return module;
} }
let module = match Py::<PyModule>::cast_from_owned_ptr(py, module) { let module = match Py::<PyModule>::cast_from_owned_ptr(py.token(), module) {
Ok(m) => m, Ok(m) => m,
Err(e) => { Err(e) => {
PyErr::from(e).restore(py); PyErr::from(e).restore(py.token());
mem::forget(guard); mem::forget(guard);
return ptr::null_mut(); return ptr::null_mut();
} }
@ -219,7 +218,7 @@ pub unsafe fn py_module_init_impl(
let ret = match init(py, &module) { let ret = match init(py, &module) {
Ok(()) => module.into_ptr(), Ok(()) => module.into_ptr(),
Err(e) => { Err(e) => {
e.restore(py); e.restore(py.token());
ptr::null_mut() ptr::null_mut()
} }
}; };

View file

@ -7,7 +7,7 @@ use std::cmp::Ordering;
use ffi; use ffi;
use libc; use libc;
use pyptr::{Py, PyPtr}; use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer}; use python::{Python, ToPythonPointer, Token, PythonObjectWithToken};
use objects::{PyObject, PyDict, PyString}; use objects::{PyObject, PyDict, PyString};
use conversion::{ToPyObject, ToPyTuple}; use conversion::{ToPyObject, ToPyTuple};
use err::{PyErr, PyResult, self}; use err::{PyErr, PyResult, self};
@ -19,7 +19,7 @@ impl<'p, T> Py<'p, T> {
/// This is equivalent to the Python expression 'hasattr(self, attr_name)'. /// This is equivalent to the Python expression 'hasattr(self, attr_name)'.
#[inline] #[inline]
pub fn hasattr<N>(&self, attr_name: N) -> PyResult<bool> where N: ToPyObject { pub fn hasattr<N>(&self, attr_name: N) -> PyResult<bool> where N: ToPyObject {
attr_name.with_borrowed_ptr(self.py(), |attr_name| unsafe { attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
Ok(ffi::PyObject_HasAttr(self.as_ptr(), attr_name) != 0) Ok(ffi::PyObject_HasAttr(self.as_ptr(), attr_name) != 0)
}) })
} }
@ -27,10 +27,11 @@ impl<'p, T> Py<'p, T> {
/// Retrieves an attribute value. /// Retrieves an attribute value.
/// This is equivalent to the Python expression 'self.attr_name'. /// This is equivalent to the Python expression 'self.attr_name'.
#[inline] #[inline]
pub fn getattr<N>(&self, attr_name: N) -> PyResult<Py<'p, PyObject>> where N: ToPyObject pub fn getattr<N>(&self, attr_name: N) -> PyResult<PyPtr<PyObject>> where N: ToPyObject
{ {
attr_name.with_borrowed_ptr(self.py(), |attr_name| unsafe { attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
Py::from_owned_ptr_or_err(self.py(), ffi::PyObject_GetAttr(self.as_ptr(), attr_name)) PyPtr::from_owned_ptr_or_err(
self.token(), ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
}) })
} }
@ -41,10 +42,10 @@ impl<'p, T> Py<'p, T> {
where N: ToPyObject, V: ToPyObject where N: ToPyObject, V: ToPyObject
{ {
attr_name.with_borrowed_ptr( attr_name.with_borrowed_ptr(
self.py(), move |attr_name| self.token(), move |attr_name|
value.with_borrowed_ptr(self.py(), |value| unsafe { value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone( err::error_on_minusone(
self.py(), ffi::PyObject_SetAttr(self.as_ptr(), attr_name, value)) self.token(), ffi::PyObject_SetAttr(self.as_ptr(), attr_name, value))
})) }))
} }
@ -52,8 +53,8 @@ impl<'p, T> Py<'p, T> {
/// This is equivalent to the Python expression 'del self.attr_name'. /// This is equivalent to the Python expression 'del self.attr_name'.
#[inline] #[inline]
pub fn delattr<N>(&self, attr_name: N) -> PyResult<()> where N: ToPyObject { pub fn delattr<N>(&self, attr_name: N) -> PyResult<()> where N: ToPyObject {
attr_name.with_borrowed_ptr(self.py(), |attr_name| unsafe { attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
err::error_on_minusone(self.py(), err::error_on_minusone(self.token(),
ffi::PyObject_DelAttr(self.as_ptr(), attr_name)) ffi::PyObject_DelAttr(self.as_ptr(), attr_name))
}) })
} }
@ -73,8 +74,8 @@ impl<'p, T> Py<'p, T> {
/// else: /// else:
/// raise TypeError("ObjectProtocol::compare(): All comparisons returned false") /// raise TypeError("ObjectProtocol::compare(): All comparisons returned false")
/// ``` /// ```
pub fn compare<O>(&self, other: O) -> PyResult<Ordering> where O: ToPyObject { /*pub fn compare<O>(&self, other: O) -> PyResult<Ordering> where O: ToPyObject {
unsafe fn do_compare(py: Python, unsafe fn do_compare(py: Token,
a: *mut ffi::PyObject, a: *mut ffi::PyObject,
b: *mut ffi::PyObject) -> PyResult<Ordering> { b: *mut ffi::PyObject) -> PyResult<Ordering> {
let result = ffi::PyObject_RichCompareBool(a, b, ffi::Py_EQ); let result = ffi::PyObject_RichCompareBool(a, b, ffi::Py_EQ);
@ -99,9 +100,9 @@ impl<'p, T> Py<'p, T> {
} }
other.with_borrowed_ptr(self.py(), |other| unsafe { other.with_borrowed_ptr(self.py(), |other| unsafe {
do_compare(self.py(), self.as_ptr(), other) do_compare(self.token(), self.as_ptr(), other)
}) })
} }*/
/// Compares two Python objects. /// Compares two Python objects.
/// ///
@ -112,29 +113,29 @@ impl<'p, T> Py<'p, T> {
/// * CompareOp::Le: `self <= other` /// * CompareOp::Le: `self <= other`
/// * CompareOp::Gt: `self > other` /// * CompareOp::Gt: `self > other`
/// * CompareOp::Ge: `self >= other` /// * CompareOp::Ge: `self >= other`
pub fn rich_compare<O>(&self, other: O, compare_op: ::CompareOp) /*pub fn rich_compare<O>(&self, other: O, compare_op: ::CompareOp)
-> PyResult<Py<'p, PyObject>> where O: ToPyObject { -> PyResult<PyPtr<PyObject>> where O: ToPyObject {
unsafe { unsafe {
other.with_borrowed_ptr(self.py(), |other| { other.with_borrowed_ptr(self.token(), |other| {
Py::cast_from_owned_nullptr( Py::cast_from_owned_nullptr(
self.py(), ffi::PyObject_RichCompare( self.token(), ffi::PyObject_RichCompare(
self.as_ptr(), other, compare_op as libc::c_int)) self.as_ptr(), other, compare_op as libc::c_int))
}) })
} }
} }*/
/// Compute the string representation of self. /// Compute the string representation of self.
/// This is equivalent to the Python expression 'repr(self)'. /// This is equivalent to the Python expression 'repr(self)'.
#[inline] #[inline]
pub fn repr(&'p self) -> PyResult<Py<'p, PyString>> { pub fn repr(&'p self) -> PyResult<Py<'p, PyString>> {
unsafe { Py::cast_from_owned_nullptr(self.py(), ffi::PyObject_Repr(self.as_ptr())) } unsafe { Py::cast_from_owned_nullptr(self.token(), ffi::PyObject_Repr(self.as_ptr())) }
} }
/// Compute the string representation of self. /// Compute the string representation of self.
/// This is equivalent to the Python expression 'str(self)'. /// This is equivalent to the Python expression 'str(self)'.
#[inline] #[inline]
pub fn str(&'p self) -> PyResult<Py<'p, PyString>> { pub fn str(&'p self) -> PyResult<Py<'p, PyString>> {
unsafe { Py::cast_from_owned_nullptr(self.py(), ffi::PyObject_Str(self.as_ptr())) } unsafe { Py::cast_from_owned_nullptr(self.token(), ffi::PyObject_Str(self.as_ptr())) }
} }
/// Determines whether this object is callable. /// Determines whether this object is callable.
@ -145,13 +146,13 @@ impl<'p, T> Py<'p, T> {
} }
} }
/// Calls the object. /* /// Calls the object.
/// This is equivalent to the Python expression: 'self(*args, **kwargs)' /// This is equivalent to the Python expression: 'self(*args, **kwargs)'
#[inline] #[inline]
pub fn call<'a, A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<Py<'p, PyObject>> pub fn call<'a, A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<Py<'p, PyObject>>
where A: ToPyTuple where A: ToPyTuple
{ {
let t = args.to_py_tuple(self.py()); let t = args.to_py_tuple(self.token());
unsafe { unsafe {
Py::from_owned_ptr_or_err( Py::from_owned_ptr_or_err(
self.py(), ffi::PyObject_Call(self.as_ptr(), t.as_ptr(), kwargs.as_ptr())) self.py(), ffi::PyObject_Call(self.as_ptr(), t.as_ptr(), kwargs.as_ptr()))
@ -167,7 +168,7 @@ impl<'p, T> Py<'p, T> {
where A: ToPyTuple where A: ToPyTuple
{ {
self.getattr(name)?.call(args, kwargs) self.getattr(name)?.call(args, kwargs)
} }*/
/// Retrieves the hash code of the object. /// Retrieves the hash code of the object.
/// This is equivalent to the Python expression: 'hash(self)' /// This is equivalent to the Python expression: 'hash(self)'
@ -175,7 +176,7 @@ impl<'p, T> Py<'p, T> {
pub fn hash(&self) -> PyResult<::Py_hash_t> { pub fn hash(&self) -> PyResult<::Py_hash_t> {
let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) }; let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::fetch(self.py())) Err(PyErr::fetch(self.token()))
} else { } else {
Ok(v) Ok(v)
} }
@ -187,7 +188,7 @@ impl<'p, T> Py<'p, T> {
pub fn is_true(&self) -> PyResult<bool> { pub fn is_true(&self) -> PyResult<bool> {
let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) }; let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::fetch(self.py())) Err(PyErr::fetch(self.token()))
} else { } else {
Ok(v != 0) Ok(v != 0)
} }
@ -199,7 +200,7 @@ impl<'p, T> Py<'p, T> {
pub fn len(&self) -> PyResult<usize> { pub fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyObject_Size(self.as_ptr()) }; let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::fetch(self.py())) Err(PyErr::fetch(self.token()))
} else { } else {
Ok(v as usize) Ok(v as usize)
} }
@ -207,9 +208,10 @@ impl<'p, T> Py<'p, T> {
/// This is equivalent to the Python expression: 'self[key]' /// This is equivalent to the Python expression: 'self[key]'
#[inline] #[inline]
pub fn get_item<K>(&self, key: K) -> PyResult<Py<'p, PyObject>> where K: ToPyObject { pub fn get_item<K>(&'p self, key: K) -> PyResult<Py<'p, PyObject>> where K: ToPyObject {
key.with_borrowed_ptr(self.py(), |key| unsafe { key.with_borrowed_ptr(self.token(), |key| unsafe {
Py::from_owned_ptr_or_err(self.py(), ffi::PyObject_GetItem(self.as_ptr(), key)) Py::from_owned_ptr_or_err(
self.token(), ffi::PyObject_GetItem(self.as_ptr(), key))
}) })
} }
@ -220,9 +222,9 @@ impl<'p, T> Py<'p, T> {
where K: ToPyObject, V: ToPyObject where K: ToPyObject, V: ToPyObject
{ {
key.with_borrowed_ptr( key.with_borrowed_ptr(
self.py(), move |key| self.token(), move |key|
value.with_borrowed_ptr(self.py(), |value| unsafe { value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone(self.py(), err::error_on_minusone(self.token(),
ffi::PyObject_SetItem(self.as_ptr(), key, value)) ffi::PyObject_SetItem(self.as_ptr(), key, value))
})) }))
} }
@ -230,9 +232,9 @@ impl<'p, T> Py<'p, T> {
/// Deletes an item. /// Deletes an item.
/// This is equivalent to the Python expression 'del self[key]'. /// This is equivalent to the Python expression 'del self[key]'.
#[inline] #[inline]
pub fn del_item<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject { pub fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe { key.with_borrowed_ptr(self.token(), |key| unsafe {
err::error_on_minusone(py, err::error_on_minusone(self.token(),
ffi::PyObject_DelItem(self.as_ptr(), key)) ffi::PyObject_DelItem(self.as_ptr(), key))
}) })
} }
@ -271,7 +273,7 @@ impl<T> fmt::Debug for PyPtr<T> {
let py = gil.python(); let py = gil.python();
// TODO: we shouldn't use fmt::Error when repr() fails // TODO: we shouldn't use fmt::Error when repr() fails
let r = self.as_ref(py); let r = self.as_ref(py.token());
let repr_obj = try!(r.repr().map_err(|_| fmt::Error)); let repr_obj = try!(r.repr().map_err(|_| fmt::Error));
f.write_str(&repr_obj.to_string_lossy()) f.write_str(&repr_obj.to_string_lossy())
} }
@ -283,7 +285,7 @@ impl<T> fmt::Display for PyPtr<T> {
let py = gil.python(); let py = gil.python();
// TODO: we shouldn't use fmt::Error when repr() fails // TODO: we shouldn't use fmt::Error when repr() fails
let r = self.as_ref(py); let r = self.as_ref(py.token());
let repr_obj = try!(r.str().map_err(|_| fmt::Error)); let repr_obj = try!(r.str().map_err(|_| fmt::Error));
f.write_str(&repr_obj.to_string_lossy()) f.write_str(&repr_obj.to_string_lossy())
} }

View file

@ -1,17 +1,17 @@
use ::{Py, PyObject}; use ::{Py, PyPtr, PyObject};
use ffi; use ffi;
use python::{Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, Token};
use conversion::{ToPyObject}; use conversion::{ToPyObject};
/// Represents a Python `bool`. /// Represents a Python `bool`.
pub struct PyBool; pub struct PyBool(PythonToken<PyBool>);
pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type); pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type);
impl PyBool { impl PyBool {
/// Depending on `val`, returns `py.True()` or `py.False()`. /// Depending on `val`, returns `py.True()` or `py.False()`.
#[inline] #[inline]
pub fn get<'p>(py: Python<'p>, val: bool) -> Py<'p, PyBool> { pub fn get(py: Token, val: bool) -> PyPtr<PyBool> {
if val { py.True() } else { py.False() } if val { py.True() } else { py.False() }
} }
@ -25,12 +25,12 @@ impl PyBool {
/// Converts a rust `bool` to a Python `bool`. /// Converts a rust `bool` to a Python `bool`.
impl ToPyObject for bool { impl ToPyObject for bool {
#[inline] #[inline]
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyBool::get(py, *self).into_object() PyBool::get(py, *self).into_object()
} }
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R fn with_borrowed_ptr<F, R>(&self, _py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R where F: FnOnce(*mut ffi::PyObject) -> R
{ {
// Avoid unnecessary Py_INCREF/Py_DECREF pair // Avoid unnecessary Py_INCREF/Py_DECREF pair

View file

@ -4,13 +4,13 @@ use std;
use std::ptr; use std::ptr;
use std::os::raw::c_char; use std::os::raw::c_char;
use ffi; use ffi;
use python::{Python, ToPythonPointer, AsPy}; use python::{Python, PythonToken, ToPythonPointer, Token};
use objects::PyObject; use objects::PyObject;
use err::{PyResult, PyErr}; use err::{PyResult, PyErr};
use pyptr::Py; use pyptr::Py;
/// Represents a Python bytearray. /// Represents a Python bytearray.
pub struct PyByteArray; pub struct PyByteArray(PythonToken<PyByteArray>);
pyobject_newtype!(PyByteArray, PyByteArray_Check, PyByteArray_Type); pyobject_newtype!(PyByteArray, PyByteArray_Check, PyByteArray_Type);
@ -20,7 +20,7 @@ impl PyByteArray {
/// The byte string is initialized by copying the data from the `&[u8]`. /// The byte string is initialized by copying the data from the `&[u8]`.
/// ///
/// Panics if out of memory. /// Panics if out of memory.
pub fn new<'p>(py: Python<'p>, src: &[u8]) -> Py<'p, PyByteArray> { pub fn new<'p>(py: Token<'p>, src: &[u8]) -> Py<'p, PyByteArray> {
let ptr = src.as_ptr() as *const c_char; let ptr = src.as_ptr() as *const c_char;
let len = src.len() as ffi::Py_ssize_t; let len = src.len() as ffi::Py_ssize_t;
let ptr = unsafe {ffi::PyByteArray_FromStringAndSize(ptr, len)}; let ptr = unsafe {ffi::PyByteArray_FromStringAndSize(ptr, len)};

View file

@ -3,15 +3,15 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ffi; use ffi;
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::{AsPy, Python, ToPythonPointer}; use python::{Python, Token, PythonToken, ToPythonPointer, PythonObjectWithToken};
use conversion::ToPyObject; use conversion::ToPyObject;
use objects::{PyObject, PyList}; use objects::{PyObject}; //, PyList};
use err::{self, PyResult, PyErr}; use err::{self, PyResult, PyErr};
use std::{mem, collections, hash, cmp}; use std::{mem, collections, hash, cmp};
/// Represents a Python `dict`. /// Represents a Python `dict`.
pub struct PyDict; pub struct PyDict(PythonToken<PyDict>);
pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type); pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type);
@ -20,15 +20,15 @@ impl PyDict {
/// Creates a new empty dictionary. /// Creates a new empty dictionary.
/// ///
/// May panic when running out of memory. /// May panic when running out of memory.
pub fn new<'p>(py: Python<'p>) -> Py<'p, PyDict> { pub fn new(py: Token) -> Py<PyDict> {
unsafe { Py::<PyDict>::cast_from_owned_ptr_or_panic(py, ffi::PyDict_New()) } unsafe { Py::from_owned_ptr_or_panic(py, ffi::PyDict_New()) }
} }
/// Return a new dictionary that contains the same key-value pairs as self. /// Return a new dictionary that contains the same key-value pairs as self.
/// Corresponds to `dict(self)` in Python. /// Corresponds to `dict(self)` in Python.
pub fn copy<'p>(&'p self) -> PyResult<Py<'p, PyDict>> { pub fn copy<'p>(&'p self) -> PyResult<PyPtr<PyDict>> {
unsafe { unsafe {
Py::from_owned_ptr_or_err(self.py(), ffi::PyDict_Copy(self.as_ptr())) PyPtr::from_owned_ptr_or_err(self.token(), ffi::PyDict_Copy(self.as_ptr()))
} }
} }
@ -48,20 +48,20 @@ impl PyDict {
/// Determine if the dictionary contains the specified key. /// Determine if the dictionary contains the specified key.
/// This is equivalent to the Python expression `key in self`. /// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject { pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(self.py(), |key| unsafe { key.with_borrowed_ptr(self.token(), |key| unsafe {
match ffi::PyDict_Contains(self.as_ptr(), key) { match ffi::PyDict_Contains(self.as_ptr(), key) {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::fetch(self.py())) _ => Err(PyErr::fetch(self.token()))
} }
}) })
} }
/// Gets an item from the dictionary. /// Gets an item from the dictionary.
/// Returns None if the item is not present, or if an error occurs. /// Returns None if the item is not present, or if an error occurs.
pub fn get_item<'p, K>(&'p self, key: K) -> Option<Py<'p, PyObject>> where K: ToPyObject { pub fn get_item<K>(&self, key: K) -> Option<&PyObject> where K: ToPyObject {
key.with_borrowed_ptr(self.py(), |key| unsafe { key.with_borrowed_ptr(self.token(), |key| unsafe {
Py::from_borrowed_ptr_opt(self.py(), ffi::PyDict_GetItem(self.as_ptr(), key)) self.token().from_owned_ptr_opt(ffi::PyDict_GetItem(self.as_ptr(), key))
}) })
} }
@ -69,57 +69,55 @@ impl PyDict {
/// This is equivalent to the Python expression `self[key] = value`. /// This is equivalent to the Python expression `self[key] = value`.
pub fn set_item<K, V>(&self, key: K, value: V) pub fn set_item<K, V>(&self, key: K, value: V)
-> PyResult<()> where K: ToPyObject, V: ToPyObject { -> PyResult<()> where K: ToPyObject, V: ToPyObject {
let py = self.py();
key.with_borrowed_ptr( key.with_borrowed_ptr(
self.py(), move |key| self.token(), move |key|
value.with_borrowed_ptr(py, |value| unsafe { value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone( err::error_on_minusone(
py, ffi::PyDict_SetItem(self.as_ptr(), key, value)) self.token(), ffi::PyDict_SetItem(self.as_ptr(), key, value))
})) }))
} }
/// Deletes an item. /// Deletes an item.
/// This is equivalent to the Python expression `del self[key]`. /// This is equivalent to the Python expression `del self[key]`.
pub fn del_item<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject { pub fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe { key.with_borrowed_ptr(self.token(), |key| unsafe {
err::error_on_minusone( err::error_on_minusone(
py, ffi::PyDict_DelItem(self.as_ptr(), key)) self.token(), ffi::PyDict_DelItem(self.as_ptr(), key))
}) })
} }
// List of dict items. // List of dict items.
// This is equivalent to the python expression `list(dict.items())`. // This is equivalent to the python expression `list(dict.items())`.
pub fn items_list(&self) -> Py<PyList> { //pub fn items_list(&self) -> Py<PyList> {
unsafe { // unsafe {
Py::from_owned_ptr_or_panic(self.py(), ffi::PyDict_Items(self.as_ptr())) // Py::from_owned_ptr_or_panic(self.py(), ffi::PyDict_Items(self.as_ptr()))
} // }
} //}
/// Returns the list of (key, value) pairs in this dictionary. /// Returns the list of (key, value) pairs in this dictionary.
pub fn items(&self) -> Vec<(Py<PyObject>, Py<PyObject>)> { pub fn items(&self) -> Vec<(&PyObject, &PyObject)> {
// Note that we don't provide an iterator because // Note that we don't provide an iterator because
// PyDict_Next() is unsafe to use when the dictionary might be changed // PyDict_Next() is unsafe to use when the dictionary might be changed
// by other python code. // by other python code.
let py = self.py(); let token = self.token();
let mut vec = Vec::with_capacity(self.len()); let mut vec = Vec::with_capacity(self.len());
unsafe { unsafe {
let mut pos = 0; let mut pos = 0;
let mut key: *mut ffi::PyObject = mem::uninitialized(); let mut key: *mut ffi::PyObject = mem::uninitialized();
let mut value: *mut ffi::PyObject = mem::uninitialized(); let mut value: *mut ffi::PyObject = mem::uninitialized();
while ffi::PyDict_Next(self.as_ptr(), &mut pos, &mut key, &mut value) != 0 { while ffi::PyDict_Next(self.as_ptr(), &mut pos, &mut key, &mut value) != 0 {
vec.push((PyObject::from_borrowed_ptr(py, key), vec.push((token.from_owned_ptr(key), token.from_owned_ptr(value)));
PyObject::from_borrowed_ptr(py, value)));
} }
} }
vec vec
} }
} }
impl <K, V> ToPyObject for collections::HashMap<K, V> /*impl <K, V> ToPyObject for collections::HashMap<K, V>
where K: hash::Hash+cmp::Eq+ToPyObject, where K: hash::Hash+cmp::Eq+ToPyObject,
V: ToPyObject V: ToPyObject
{ {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
let dict = PyDict::new(py); let dict = PyDict::new(py);
for (key, value) in self { for (key, value) in self {
dict.set_item(key, value).unwrap(); dict.set_item(key, value).unwrap();
@ -132,14 +130,14 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
where K: cmp::Eq+ToPyObject, where K: cmp::Eq+ToPyObject,
V: ToPyObject V: ToPyObject
{ {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
let dict = PyDict::new(py); let dict = PyDict::new(py);
for (key, value) in self { for (key, value) in self {
dict.set_item(key, value).unwrap(); dict.set_item(key, value).unwrap();
}; };
dict.into_object() dict.into_pptr().into_object()
}
} }
}*/
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View file

@ -9,8 +9,8 @@ use std::{self, mem, ops};
use std::ffi::CStr; use std::ffi::CStr;
use ffi; use ffi;
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer}; use python::{Python, ToPythonPointer, Token};
use err::PyResult; use err::PyResult;
use super::tuple::PyTuple; use super::tuple::PyTuple;
use super::typeobject::PyType; use super::typeobject::PyType;
@ -23,7 +23,7 @@ macro_rules! exc_type(
impl $crate::PyTypeObject for $name { impl $crate::PyTypeObject for $name {
#[inline] #[inline]
fn type_object<'p>(py: $crate::Python<'p>) -> $crate::Py<'p, PyType> { fn type_object(py: $crate::python::Token) -> $crate::PyPtr<PyType> {
unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) } unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) }
} }
} }
@ -84,12 +84,11 @@ exc_type!(UnicodeTranslateError, PyExc_UnicodeTranslateError);
impl UnicodeDecodeError { impl UnicodeDecodeError {
pub fn new<'p>(py: Python<'p>, encoding: &CStr, input: &[u8], pub fn new(py: Token, encoding: &CStr, input: &[u8], range: ops::Range<usize>, reason: &CStr)
range: ops::Range<usize>, reason: &CStr) -> PyResult<PyPtr<UnicodeDecodeError>> {
-> PyResult<Py<'p, UnicodeDecodeError>> {
unsafe { unsafe {
let input: &[c_char] = mem::transmute(input); let input: &[c_char] = mem::transmute(input);
Py::from_owned_ptr_or_err( PyPtr::from_owned_ptr_or_err(
py, ffi::PyUnicodeDecodeError_Create( py, ffi::PyUnicodeDecodeError_Create(
encoding.as_ptr(), encoding.as_ptr(),
input.as_ptr(), input.as_ptr(),
@ -100,9 +99,8 @@ impl UnicodeDecodeError {
} }
} }
pub fn new_utf8<'p>(py: Python<'p>, input: &[u8], pub fn new_utf8<'p>(py: Token, input: &[u8], err: std::str::Utf8Error)
err: std::str::Utf8Error) -> PyResult<PyPtr<UnicodeDecodeError>>
-> PyResult<Py<'p, UnicodeDecodeError>>
{ {
let pos = err.valid_up_to(); let pos = err.valid_up_to();
UnicodeDecodeError::new(py, cstr!("utf-8"), input, pos .. pos+1, cstr!("invalid utf-8")) UnicodeDecodeError::new(py, cstr!("utf-8"), input, pos .. pos+1, cstr!("invalid utf-8"))

View file

@ -3,13 +3,14 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use pyptr::Py; use pyptr::Py;
use python::{AsPy, Python, ToPythonPointer, IntoPythonPointer}; use python::{Python, ToPythonPointer, IntoPythonPointer,
PythonToken, PythonObjectWithToken, PythonTokenApi};
use objects::PyObject; use objects::PyObject;
use ffi::{self, Py_ssize_t}; use ffi::{self, Py_ssize_t};
use conversion::{ToPyObject, IntoPyObject}; use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `list`. /// Represents a Python `list`.
pub struct PyList; pub struct PyList(PythonToken<PyList>);
pyobject_newtype!(PyList, PyList_Check, PyList_Type); pyobject_newtype!(PyList, PyList_Check, PyList_Type);
@ -38,12 +39,12 @@ impl PyList {
/// Gets the item at the specified index. /// Gets the item at the specified index.
/// ///
/// Panics if the index is out of range. /// Panics if the index is out of range.
pub fn get_item<'p>(&'p self, index: usize) -> Py<'p, PyObject> { pub fn get_item(&self, index: usize) -> &PyObject {
// TODO: do we really want to panic here? // TODO: do we really want to panic here?
assert!(index < self.len()); assert!(index < self.len());
unsafe { unsafe {
Py::from_borrowed_ptr( let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
self.py(), ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)) self.py_token().from_owned(ptr)
} }
} }

View file

@ -6,13 +6,13 @@ pub use self::module::PyModule;
pub use self::string::{PyBytes, PyString, PyStringData}; pub use self::string::{PyBytes, PyString, PyStringData};
//pub use self::iterator::PyIterator; //pub use self::iterator::PyIterator;
pub use self::boolobject::PyBool; pub use self::boolobject::PyBool;
pub use self::bytearray::PyByteArray; //pub use self::bytearray::PyByteArray;
pub use self::tuple::{PyTuple, NoArgs}; pub use self::tuple::{PyTuple, NoArgs};
pub use self::dict::PyDict; pub use self::dict::PyDict;
pub use self::list::PyList; //pub use self::list::PyList;
pub use self::num::{PyLong, PyFloat}; pub use self::num::{PyLong, PyFloat};
//pub use self::sequence::PySequence; //pub use self::sequence::PySequence;
pub use self::slice::PySlice; //pub use self::slice::PySlice;
//pub use self::set::{PySet, PyFrozenSet}; //pub use self::set::{PySet, PyFrozenSet};
@ -20,27 +20,6 @@ pub use self::slice::PySlice;
macro_rules! pyobject_newtype( macro_rules! pyobject_newtype(
($name: ident, $checkfunction: ident, $typeobject: ident) => ( ($name: ident, $checkfunction: ident, $typeobject: ident) => (
impl<'p> $crate::python::AsPy<'p> for &'p $name {
#[inline]
fn py<'a>(&'a self) -> $crate::Python<'p> {
unsafe { $crate::python::Python::assume_gil_acquired() }
}
}
impl $crate::python::ToPythonPointer for $name {
#[inline]
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut $crate::ffi::PyObject
}
}
impl<'a> $crate::python::ToPythonPointer for &'a $name {
#[inline]
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut $crate::ffi::PyObject
}
}
impl $crate::typeob::PyTypeInfo for $name { impl $crate::typeob::PyTypeInfo for $name {
type Type = (); type Type = ();
@ -64,11 +43,17 @@ macro_rules! pyobject_newtype(
} }
} }
impl $crate::python::PythonObjectWithToken for $name {
fn token<'p>(&'p self) -> $crate::python::Token<'p> {
self.0.token()
}
}
impl $crate::std::fmt::Debug for $name { impl $crate::std::fmt::Debug for $name {
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter) default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error> -> Result<(), $crate::std::fmt::Error>
{ {
let py = unsafe { $crate::python::Python::assume_gil_acquired() }; let py = <$name as $crate::python::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr( let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
py, $crate::ffi::PyObject_Repr( py, $crate::ffi::PyObject_Repr(
$crate::python::ToPythonPointer::as_ptr(self))) }; $crate::python::ToPythonPointer::as_ptr(self))) };
@ -81,7 +66,7 @@ macro_rules! pyobject_newtype(
fn fmt(&self, f: &mut $crate::std::fmt::Formatter) fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error> -> Result<(), $crate::std::fmt::Error>
{ {
let py = unsafe { $crate::python::Python::assume_gil_acquired() }; let py = <$name as $crate::python::PythonObjectWithToken>::token(self);
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr( let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
py, $crate::ffi::PyObject_Str( py, $crate::ffi::PyObject_Str(
$crate::python::ToPythonPointer::as_ptr(self))) }; $crate::python::ToPythonPointer::as_ptr(self))) };
@ -113,12 +98,12 @@ mod string;
mod dict; mod dict;
//mod iterator; //mod iterator;
mod boolobject; mod boolobject;
mod bytearray; //mod bytearray;
mod tuple; mod tuple;
mod list; //mod list;
mod num; mod num;
//mod sequence; //mod sequence;
mod slice; //mod slice;
// mod set; // mod set;
mod object; mod object;
pub mod exc; pub mod exc;

View file

@ -7,19 +7,19 @@ use ffi;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::{AsPy, Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, PythonObjectWithToken, Token};
use objects::{PyObject, PyDict, PyType, exc}; use objects::{PyObject, PyDict, PyType, exc};
use err::{PyResult, PyErr}; use err::{PyResult, PyErr};
/// Represents a Python module object. /// Represents a Python module object.
pub struct PyModule; pub struct PyModule(PythonToken<PyModule>);
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type); pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
impl PyModule { impl PyModule {
/// Create a new module object with the `__name__` attribute set to name. /// 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<'p>(py: Token<'p>, name: &str) -> PyResult<Py<'p, PyModule>> {
let name = CString::new(name).unwrap(); let name = CString::new(name).unwrap();
unsafe { unsafe {
Py::cast_from_owned_nullptr(py, ffi::PyModule_New(name.as_ptr())) Py::cast_from_owned_nullptr(py, ffi::PyModule_New(name.as_ptr()))
@ -27,7 +27,7 @@ impl PyModule {
} }
/// Import the Python module with the specified name. /// Import the Python module with the specified name.
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<Py<'p, PyModule>> { pub fn import<'p>(py: Token<'p>, name: &str) -> PyResult<Py<'p, PyModule>> {
let name = CString::new(name).unwrap(); let name = CString::new(name).unwrap();
unsafe { unsafe {
Py::cast_from_owned_nullptr(py, ffi::PyImport_ImportModule(name.as_ptr())) Py::cast_from_owned_nullptr(py, ffi::PyImport_ImportModule(name.as_ptr()))
@ -36,21 +36,21 @@ impl PyModule {
/// Return the dictionary object that implements module's namespace; /// Return the dictionary object that implements module's namespace;
/// this object is the same as the `__dict__` attribute of the module object. /// this object is the same as the `__dict__` attribute of the module object.
pub fn dict(&self) -> Py<PyDict> { pub fn dict(&self) -> PyPtr<PyDict> {
unsafe { unsafe {
Py::from_borrowed_ptr(self.py(), ffi::PyModule_GetDict(self.as_ptr())) PyPtr::from_borrowed_ptr(ffi::PyModule_GetDict(self.as_ptr()))
} }
} }
unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char) -> PyResult<&'a str> { unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char) -> PyResult<&'a str> {
if ptr.is_null() { if ptr.is_null() {
Err(PyErr::fetch(self.py())) Err(PyErr::fetch(self.token()))
} else { } else {
let slice = CStr::from_ptr(ptr).to_bytes(); let slice = CStr::from_ptr(ptr).to_bytes();
match std::str::from_utf8(slice) { match std::str::from_utf8(slice) {
Ok(s) => Ok(s), Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance( Err(e) => Err(PyErr::from_instance(
self.py(), try!(exc::UnicodeDecodeError::new_utf8(self.py(), slice, e)))) self.token(), try!(exc::UnicodeDecodeError::new_utf8(self.token(), slice, e))))
} }
} }
} }
@ -81,17 +81,18 @@ impl PyModule {
let type_name = <T as ::typeob::PyTypeInfo>::type_name(); let type_name = <T as ::typeob::PyTypeInfo>::type_name();
let ty = if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 { let ty = if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
unsafe { PyType::from_type_ptr(self.py(), ty) } unsafe { PyType::from_type_ptr(self.token(), ty) }
} else { } else {
// automatically initialize the class // automatically initialize the class
let name = self.name()?; let name = self.name()?;
::typeob::initialize_type::<T>(self.py(), Some(name), type_name, ty) ::typeob::initialize_type::<T>(self.token(), Some(name), type_name, ty)
.expect( .expect(
format!("An error occurred while initializing class {}", format!("An error occurred while initializing class {}",
<T as ::typeob::PyTypeInfo>::type_name()).as_ref()); <T as ::typeob::PyTypeInfo>::type_name()).as_ref());
unsafe { PyType::from_type_ptr(self.py(), ty) } unsafe { PyType::from_type_ptr(self.token(), ty) }
}; };
PyObject::from_borrowed_ptr(self.py(), self.as_ptr()).setattr(type_name, ty) // PyObject::from_borrowed_ptr(self.py(), self.as_ptr()).setattr(type_name, ty)
Ok(())
} }
} }

View file

@ -7,12 +7,12 @@ extern crate num_traits;
use self::num_traits::cast::cast; use self::num_traits::cast::cast;
use std::os::raw::{c_long, c_double}; use std::os::raw::{c_long, c_double};
use ::Py; use ::{Py, PyPtr};
use ffi; use ffi;
use super::exc; use super::exc;
use super::PyObject; use super::PyObject;
use typeob::PyTypeInfo; use typeob::PyTypeInfo;
use python::{Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, PythonObjectWithToken, Token};
use err::{PyResult, PyErr}; use err::{PyResult, PyErr};
use conversion::{ToPyObject, FromPyObject}; use conversion::{ToPyObject, FromPyObject};
@ -22,7 +22,7 @@ use conversion::{ToPyObject, FromPyObject};
/// by using [ToPyObject](trait.ToPyObject.html) /// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract) /// and [extract](struct.PyObject.html#method.extract)
/// with the primitive Rust integer types. /// with the primitive Rust integer types.
pub struct PyLong; pub struct PyLong(PythonToken<PyLong>);
pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type); pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type);
/// Represents a Python `float` object. /// Represents a Python `float` object.
@ -31,15 +31,15 @@ pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type);
/// by using [ToPyObject](trait.ToPyObject.html) /// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract) /// and [extract](struct.PyObject.html#method.extract)
/// with `f32`/`f64`. /// with `f32`/`f64`.
pub struct PyFloat; pub struct PyFloat(PythonToken<PyFloat>);
pyobject_newtype!(PyFloat, PyFloat_Check, PyFloat_Type); pyobject_newtype!(PyFloat, PyFloat_Check, PyFloat_Type);
impl PyFloat { impl PyFloat {
/// Creates a new Python `float` object. /// Creates a new Python `float` object.
pub fn new<'p>(py: Python<'p>, val: c_double) -> Py<'p, PyFloat> { pub fn new(_py: Token, val: c_double) -> PyPtr<PyFloat> {
unsafe { unsafe {
Py::from_owned_ptr_or_panic(py, ffi::PyFloat_FromDouble(val)) PyPtr::from_owned_ptr_or_panic(ffi::PyFloat_FromDouble(val))
} }
} }
@ -53,21 +53,21 @@ impl PyFloat {
macro_rules! int_fits_c_long( macro_rules! int_fits_c_long(
($rust_type:ty) => ( ($rust_type:ty) => (
impl ToPyObject for $rust_type { impl ToPyObject for $rust_type {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
unsafe { unsafe {
Py::from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(*self as c_long)) PyPtr::from_owned_ptr_or_panic(ffi::PyLong_FromLong(*self as c_long))
} }
} }
} }
pyobject_extract!(obj to $rust_type => { pyobject_extract!(obj to $rust_type => {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) }; let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(obj.py()) { if val == -1 && PyErr::occurred(obj.token()) {
return Err(PyErr::fetch(obj.py())); return Err(PyErr::fetch(obj.token()));
} }
match cast::<c_long, $rust_type>(val) { match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v), Some(v) => Ok(v),
None => Err(overflow_error(obj.py())) None => Err(overflow_error(obj.token()))
} }
}); });
) )
@ -78,13 +78,13 @@ macro_rules! int_fits_larger_int(
($rust_type:ty, $larger_type:ty) => ( ($rust_type:ty, $larger_type:ty) => (
impl ToPyObject for $rust_type { impl ToPyObject for $rust_type {
#[inline] #[inline]
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
(*self as $larger_type).to_object(py) (*self as $larger_type).to_object(py)
} }
} }
pyobject_extract!(obj to $rust_type => { pyobject_extract!(obj to $rust_type => {
let py = obj.py(); let py = obj.token();
let val = try!(obj.extract::<$larger_type>()); let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) { match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v), Some(v) => Ok(v),
@ -96,7 +96,7 @@ macro_rules! int_fits_larger_int(
fn err_if_invalid_value<'p, T: PartialEq> fn err_if_invalid_value<'p, T: PartialEq>
(py: Python, invalid_value: T, actual_value: T) -> PyResult<T> (py: Token, invalid_value: T, actual_value: T) -> PyResult<T>
{ {
if actual_value == invalid_value && PyErr::occurred(py) { if actual_value == invalid_value && PyErr::occurred(py) {
Err(PyErr::fetch(py)) Err(PyErr::fetch(py))
@ -109,9 +109,9 @@ macro_rules! int_convert_u64_or_i64 (
($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => ( ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => (
impl ToPyObject for $rust_type { impl ToPyObject for $rust_type {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
unsafe { unsafe {
Py::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self)) PyPtr::from_owned_ptr_or_panic($pylong_from_ll_or_ull(*self))
} }
} }
} }
@ -123,13 +123,13 @@ macro_rules! int_convert_u64_or_i64 (
let ptr = py.as_ptr(); let ptr = py.as_ptr();
unsafe { unsafe {
if ffi::PyLong_Check(ptr) != 0 { if ffi::PyLong_Check(ptr) != 0 {
err_if_invalid_value(py.py(), !0, $pylong_as_ull_or_ull(ptr)) err_if_invalid_value(py.token(), !0, $pylong_as_ull_or_ull(ptr))
} else { } else {
let num = ffi::PyNumber_Long(ptr); let num = ffi::PyNumber_Long(ptr);
if num.is_null() { if num.is_null() {
Err(PyErr::fetch(py.py())) Err(PyErr::fetch(py.token()))
} else { } else {
err_if_invalid_value(py.py(), !0, $pylong_as_ull_or_ull(num)) err_if_invalid_value(py.token(), !0, $pylong_as_ull_or_ull(num))
} }
} }
} }
@ -169,26 +169,26 @@ int_fits_larger_int!(usize, u64);
int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong); int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong);
impl ToPyObject for f64 { impl ToPyObject for f64 {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyFloat::new(py, *self).into_object() PyFloat::new(py, *self).into_object()
} }
} }
pyobject_extract!(obj to f64 => { pyobject_extract!(obj to f64 => {
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
if v == -1.0 && PyErr::occurred(obj.py()) { if v == -1.0 && PyErr::occurred(obj.token()) {
Err(PyErr::fetch(obj.py())) Err(PyErr::fetch(obj.token()))
} else { } else {
Ok(v) Ok(v)
} }
}); });
fn overflow_error(py: Python) -> PyErr { fn overflow_error(py: Token) -> PyErr {
PyErr::new_lazy_init(py.get_ptype::<exc::OverflowError>(), None) PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
} }
impl ToPyObject for f32 { impl ToPyObject for f32 {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyFloat::new(py, *self as f64).into_object() PyFloat::new(py, *self as f64).into_object()
} }
} }

View file

@ -4,21 +4,23 @@ use std;
use ffi; use ffi;
use pyptr::{Py, PyPtr}; use pyptr::{Py, PyPtr};
use python::Python; use err::{PyErr, PyResult, PyDowncastError};
use python::{Python, PythonToken, Token, PythonObjectWithToken};
use typeob::PyTypeInfo;
pub struct PyObject; pub struct PyObject(PythonToken<PyObject>);
pyobject_newtype!(PyObject, PyObject_Check, PyBaseObject_Type); pyobject_newtype!(PyObject, PyObject_Check, PyBaseObject_Type);
impl PyObject { impl PyObject {
#[inline] #[inline]
pub fn from_owned_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<PyObject> { pub fn from_owned_ptr(py: Token, ptr: *mut ffi::PyObject) -> Py<PyObject> {
unsafe { Py::from_owned_ptr(py, ptr) } unsafe { Py::from_owned_ptr(py, ptr) }
} }
#[inline] #[inline]
pub fn from_borrowed_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<PyObject> { pub fn from_borrowed_ptr(py: Token, ptr: *mut ffi::PyObject) -> Py<PyObject> {
unsafe { Py::from_borrowed_ptr(py, ptr) } unsafe { Py::from_borrowed_ptr(py, ptr) }
} }
@ -26,7 +28,7 @@ impl PyObject {
/// This moves ownership over the pointer into the PyObject. /// This moves ownership over the pointer into the PyObject.
/// Returns None for null pointers; undefined behavior if the pointer is invalid. /// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline] #[inline]
pub unsafe fn from_owned_pptr_opt(py: Python, ptr: *mut ffi::PyObject) pub unsafe fn from_owned_pptr_opt(py: Token, ptr: *mut ffi::PyObject)
-> Option<PyPtr<PyObject>> { -> Option<PyPtr<PyObject>> {
if ptr.is_null() { if ptr.is_null() {
None None
@ -37,7 +39,7 @@ impl PyObject {
/// Returns None for null pointers; undefined behavior if the pointer is invalid. /// Returns None for null pointers; undefined behavior if the pointer is invalid.
#[inline] #[inline]
pub unsafe fn from_borrowed_pptr_opt(py: Python, ptr: *mut ffi::PyObject) pub unsafe fn from_borrowed_pptr_opt(py: Token, ptr: *mut ffi::PyObject)
-> Option<PyPtr<PyObject>> { -> Option<PyPtr<PyObject>> {
if ptr.is_null() { if ptr.is_null() {
None None
@ -53,4 +55,25 @@ impl PyObject {
-> &'a [Py<'a, PyObject>] { -> &'a [Py<'a, PyObject>] {
std::mem::transmute(ptr) 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>>
where D: PyTypeInfo
{
unsafe {
let ptr = self as *const _ as *mut _;
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, D::type_object()) != 0 };
if checked {
Ok(
unsafe {
let ptr = ptr as *mut D;
ptr.as_ref().unwrap() })
} else {
Err(PyDowncastError(self.token(), None))
}
}
}
} }

View file

@ -1,9 +1,9 @@
// Copyright (c) 2017-present PyO3 Project and Contributors // Copyright (c) 2017-present PyO3 Project and Contributors
use std::os::raw::c_long; use std::os::raw::c_long;
use pyptr::Py; use pyptr::PyPtr;
use objects::PyObject; use objects::PyObject;
use python::{AsPy, Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, Token};
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use ffi::{self, Py_ssize_t}; use ffi::{self, Py_ssize_t};
use conversion::ToPyObject; use conversion::ToPyObject;
@ -30,18 +30,18 @@ impl PySliceIndices {
/// Represents a Python `slice`. Only `c_long` indeces supprted /// Represents a Python `slice`. Only `c_long` indeces supprted
/// at the moment by PySlice object. /// at the moment by PySlice object.
pub struct PySlice(PyObject); pub struct PySlice(PythonToken<PySlice>);
pyobject_newtype!(PySlice, PySlice_Check, PySlice_Type); pyobject_newtype!(PySlice, PySlice_Check, PySlice_Type);
impl PySlice { impl PySlice {
/// Construct a new slice with the given elements. /// 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<'p>(py: Token, start: isize, stop: isize, step: isize) -> PyPtr<PySlice> {
unsafe { unsafe {
let ptr = ffi::PySlice_New(ffi::PyLong_FromLong(start as i64), let ptr = ffi::PySlice_New(ffi::PyLong_FromLong(start as i64),
ffi::PyLong_FromLong(stop as i64), ffi::PyLong_FromLong(stop as i64),
ffi::PyLong_FromLong(step as i64)); ffi::PyLong_FromLong(step as i64));
Py::from_owned_ptr_or_panic(py, ptr) PyPtr::from_owned_ptr_or_panic(py, ptr)
} }
} }
@ -68,14 +68,14 @@ impl PySlice {
slicelength: slicelen, slicelength: slicelen,
}) })
} else { } else {
Err(PyErr::fetch(self.py())) Err(PyErr::fetch(self.token()))
} }
} }
} }
} }
impl ToPyObject for PySliceIndices { impl ToPyObject for PySliceIndices {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object<'p>(&self, py: Token) -> PyPtr<PyObject> {
PySlice::new(py, self.start, self.stop, self.step).into_object() PySlice::new(py, self.start, self.stop, self.step)
} }
} }

View file

@ -8,20 +8,20 @@ use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::os::raw::c_char; use std::os::raw::c_char;
use ::Py; use ::{Py, PyPtr};
use ffi; use ffi;
use python::{AsPy, Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, Token, PythonObjectWithToken};
use super::{exc, PyObject}; use super::{exc, PyObject};
use err::{PyResult, PyErr}; use err::{PyResult, PyErr};
use conversion::{ToPyObject, RefFromPyObject}; use conversion::{ToPyObject, RefFromPyObject};
/// Represents a Python string. /// Represents a Python string.
pub struct PyString; pub struct PyString(PythonToken<PyString>);
pyobject_newtype!(PyString, PyUnicode_Check, PyUnicode_Type); pyobject_newtype!(PyString, PyUnicode_Check, PyUnicode_Type);
/// Represents a Python byte string. /// Represents a Python byte string.
pub struct PyBytes; pub struct PyBytes(PythonToken<PyBytes>);
pyobject_newtype!(PyBytes, PyBytes_Check, PyBytes_Type); pyobject_newtype!(PyBytes, PyBytes_Check, PyBytes_Type);
@ -63,7 +63,7 @@ impl <'a> PyStringData<'a> {
/// For Latin-1, UTF-16 and UTF-32, returns an owned string. /// For Latin-1, UTF-16 and UTF-32, returns an owned string.
/// ///
/// Fails with UnicodeDecodeError if the string data isn't valid in its encoding. /// Fails with UnicodeDecodeError if the string data isn't valid in its encoding.
pub fn to_string(self, py: Python) -> PyResult<Cow<'a, str>> { pub fn to_string(self, py: Token) -> PyResult<Cow<'a, str>> {
match self { match self {
PyStringData::Utf8(data) => { PyStringData::Utf8(data) => {
match str::from_utf8(data) { match str::from_utf8(data) {
@ -141,20 +141,19 @@ impl PyString {
/// Use `PyUnicode::new()` to always create a unicode string. /// Use `PyUnicode::new()` to always create a unicode string.
/// ///
/// Panics if out of memory. /// Panics if out of memory.
pub fn new<'p>(py: Python<'p>, s: &str) -> Py<'p, PyString> { pub fn new<'p>(py: Token, s: &str) -> PyPtr<PyString> {
let ptr = s.as_ptr() as *const c_char; let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t; let len = s.len() as ffi::Py_ssize_t;
unsafe { unsafe {
Py::cast_from_owned_ptr_or_panic( PyPtr::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
py, ffi::PyUnicode_FromStringAndSize(ptr, len))
} }
} }
pub fn from_object<'p>(src: &'p PyObject, encoding: &str, errors: &str) pub fn from_object<'p>(src: &PyObject, encoding: &str, errors: &str)
-> PyResult<Py<'p, PyString>> { -> PyResult<PyPtr<PyString>> {
unsafe { unsafe {
Py::cast_from_owned_ptr( PyPtr::from_owned_ptr_or_err(
src.py(), ffi::PyUnicode_FromEncodedObject( src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8)) src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8))
.map_err(|e| e.into()) .map_err(|e| e.into())
} }
@ -168,7 +167,7 @@ impl PyString {
let mut size : ffi::Py_ssize_t = mem::uninitialized(); 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.as_ptr(), &mut size) as *const u8;
if data.is_null() { if data.is_null() {
PyErr::fetch(self.py()).print(self.py()); PyErr::fetch(self.token()).print(self.token());
panic!("PyUnicode_AsUTF8AndSize failed"); panic!("PyUnicode_AsUTF8AndSize failed");
} }
PyStringData::Utf8(std::slice::from_raw_parts(data, size as usize)) PyStringData::Utf8(std::slice::from_raw_parts(data, size as usize))
@ -180,7 +179,7 @@ impl PyString {
/// Returns a `UnicodeDecodeError` if the input is not valid unicode /// Returns a `UnicodeDecodeError` if the input is not valid unicode
/// (containing unpaired surrogates). /// (containing unpaired surrogates).
pub fn to_string(&self) -> PyResult<Cow<str>> { pub fn to_string(&self) -> PyResult<Cow<str>> {
self.data().to_string(self.py()) self.data().to_string(self.token())
} }
/// Convert the `PyString` into a Rust string. /// Convert the `PyString` into a Rust string.
@ -197,7 +196,7 @@ impl PyBytes {
/// The byte string is initialized by copying the data from the `&[u8]`. /// The byte string is initialized by copying the data from the `&[u8]`.
/// ///
/// Panics if out of memory. /// Panics if out of memory.
pub fn new<'p>(py: Python<'p>, s: &[u8]) -> Py<'p, PyBytes> { pub fn new<'p>(py: Token<'p>, s: &[u8]) -> Py<'p, PyBytes> {
let ptr = s.as_ptr() as *const c_char; let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t; let len = s.len() as ffi::Py_ssize_t;
unsafe { unsafe {
@ -220,7 +219,7 @@ impl PyBytes {
/// See `PyString::new` for details on the conversion. /// See `PyString::new` for details on the conversion.
impl ToPyObject for str { impl ToPyObject for str {
#[inline] #[inline]
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyString::new(py, self).into_object() PyString::new(py, self).into_object()
} }
} }
@ -229,7 +228,7 @@ impl ToPyObject for str {
/// See `PyString::new` for details on the conversion. /// See `PyString::new` for details on the conversion.
impl <'a> ToPyObject for Cow<'a, str> { impl <'a> ToPyObject for Cow<'a, str> {
#[inline] #[inline]
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyString::new(py, self).into_object() PyString::new(py, self).into_object()
} }
} }
@ -238,7 +237,7 @@ impl <'a> ToPyObject for Cow<'a, str> {
/// See `PyString::new` for details on the conversion. /// See `PyString::new` for details on the conversion.
impl ToPyObject for String { impl ToPyObject for String {
#[inline] #[inline]
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyString::new(py, self).into_object() PyString::new(py, self).into_object()
} }
} }
@ -262,7 +261,7 @@ impl<'p> RefFromPyObject<'p> for str {
fn with_extracted<F, R>(obj: &'p Py<'p, PyObject>, f: F) -> PyResult<R> fn with_extracted<F, R>(obj: &'p Py<'p, PyObject>, f: F) -> PyResult<R>
where F: FnOnce(&str) -> R where F: FnOnce(&str) -> R
{ {
let p = PyObject::from_borrowed_ptr(obj.py(), obj.as_ptr()); let p = PyObject::from_borrowed_ptr(obj.token(), obj.as_ptr());
let s = try!(p.extract::<Cow<str>>()); let s = try!(p.extract::<Cow<str>>());
Ok(f(&s)) Ok(f(&s))
} }

View file

@ -4,26 +4,27 @@
use std::slice; use std::slice;
use ::Py; use ::{Py, PyPtr};
use ffi::{self, Py_ssize_t}; use ffi::{self, Py_ssize_t};
use python::{AsPy, Python, ToPythonPointer, IntoPythonPointer}; use python::{Python, PythonToken, Token,
ToPythonPointer, IntoPythonPointer, PythonObjectWithToken};
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use conversion::{FromPyObject, ToPyObject, ToPyTuple}; use conversion::{FromPyObject, ToPyObject, ToPyTuple};
use super::exc; use super::exc;
use super::PyObject; use super::PyObject;
/// Represents a Python tuple object. /// Represents a Python tuple object.
pub struct PyTuple; pub struct PyTuple(PythonToken<PyTuple>);
pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type); pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);
impl PyTuple { impl PyTuple {
/// Construct a new tuple with the given elements. /// Construct a new tuple with the given elements.
pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> Py<'p, PyTuple> { pub fn new<'p, T: ToPyObject>(py: Token, elements: &[T]) -> PyPtr<PyTuple> {
unsafe { unsafe {
let len = elements.len(); let len = elements.len();
let ptr = ffi::PyTuple_New(len as Py_ssize_t); let ptr = ffi::PyTuple_New(len as Py_ssize_t);
let t = Py::from_owned_ptr_or_panic(py, ptr); let t = PyPtr::from_owned_ptr_or_panic(ptr);
for (i, e) in elements.iter().enumerate() { for (i, e) in elements.iter().enumerate() {
ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr()); ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr());
} }
@ -32,9 +33,9 @@ impl PyTuple {
} }
/// Retrieves the empty tuple. /// Retrieves the empty tuple.
pub fn empty<'p>(py: Python<'p>) -> Py<'p, PyTuple> { pub fn empty(py: Token) -> PyPtr<PyTuple> {
unsafe { unsafe {
Py::from_owned_ptr_or_panic(py, ffi::PyTuple_New(0)) PyPtr::from_owned_ptr_or_panic(ffi::PyTuple_New(0))
} }
} }
@ -50,14 +51,13 @@ impl PyTuple {
/// Gets the item at the specified index. /// Gets the item at the specified index.
/// ///
/// Panics if the index is out of range. /// Panics if the index is out of range.
pub fn get_item<'p>(&self, index: usize) -> Py<'p, PyObject> { pub fn get_item<'p>(&self, index: usize) -> &PyObject {
// TODO: reconsider whether we should panic // TODO: reconsider whether we should panic
// It's quite inconsistent that this method takes `Python` when `len()` does not. // It's quite inconsistent that this method takes `Python` when `len()` does not.
assert!(index < self.len()); assert!(index < self.len());
unsafe { unsafe {
std::mem::transmute( self.token().from_owned_ptr(
PyObject::from_borrowed_ptr( ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
self.py(), ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t)))
} }
} }
@ -84,27 +84,27 @@ impl PyTuple {
use std; use std;
impl<'a> ToPyTuple for Py<'a, PyTuple> { impl<'a> ToPyTuple for Py<'a, PyTuple> {
fn to_py_tuple<'p>(&self, _py: Python<'p>) -> Py<'p, PyTuple> { fn to_py_tuple(&self, _py: Token) -> PyPtr<PyTuple> {
unsafe { std::mem::transmute(self.clone()) } self.as_pptr()
} }
} }
impl<'a> ToPyTuple for &'a str { impl<'a> ToPyTuple for &'a str {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> Py<'p, PyTuple> { fn to_py_tuple(&self, py: Token) -> PyPtr<PyTuple> {
PyTuple::new(py, &[py_coerce_expr!(self.to_object(py))]) PyTuple::new(py, &[py_coerce_expr!(self.to_object(py))])
} }
} }
fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr { fn wrong_tuple_length(py: Token, t: &PyTuple, expected_length: usize) -> PyErr {
let msg = format!("Expected tuple of length {}, but got tuple of length {}.", let msg = format!("Expected tuple of length {}, but got tuple of length {}.",
expected_length, t.len()); expected_length, t.len());
PyErr::new_lazy_init( PyErr::new_lazy_init(
py.get_ptype::<exc::ValueError>(), Some(msg.to_object(py).into_pptr())) py.get_type::<exc::ValueError>(), Some(msg.to_object(py)))
} }
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => { macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => {
impl <$($T: ToPyObject),+> ToPyObject for ($($T,)+) { impl <$($T: ToPyObject),+> ToPyObject for ($($T,)+) {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyTuple::new(py, &[ PyTuple::new(py, &[
$(py_coerce_expr!(self.$n.to_object(py)),)+ $(py_coerce_expr!(self.$n.to_object(py)),)+
]).into_object() ]).into_object()
@ -112,7 +112,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
} }
impl <$($T: ToPyObject),+> ToPyTuple for ($($T,)+) { impl <$($T: ToPyObject),+> ToPyTuple for ($($T,)+) {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> Py<'p, PyTuple> { fn to_py_tuple(&self, py: Token) -> PyPtr<PyTuple> {
PyTuple::new(py, &[ PyTuple::new(py, &[
$(py_coerce_expr!(self.$n.to_object(py)),)+ $(py_coerce_expr!(self.$n.to_object(py)),)+
]) ])
@ -130,7 +130,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
$( try!(slice[$n].extract::<$T>()), )+ $( try!(slice[$n].extract::<$T>()), )+
)) ))
} else { } else {
Err(wrong_tuple_length(obj.py(), t, $length)) Err(wrong_tuple_length(obj.token(), t, $length))
} }
} }
} }
@ -169,7 +169,7 @@ pub struct NoArgs;
/// Converts `NoArgs` to an empty Python tuple. /// Converts `NoArgs` to an empty Python tuple.
impl ToPyObject for NoArgs { impl ToPyObject for NoArgs {
fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { fn to_object(&self, py: Token) -> PyPtr<PyObject> {
PyTuple::empty(py).into_object() PyTuple::empty(py).into_object()
} }
} }
@ -177,7 +177,7 @@ impl ToPyObject for NoArgs {
/// Converts `NoArgs` to an empty Python tuple. /// Converts `NoArgs` to an empty Python tuple.
impl ToPyTuple for NoArgs { impl ToPyTuple for NoArgs {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> Py<'p, PyTuple> { fn to_py_tuple(&self, py: Token) -> PyPtr<PyTuple> {
PyTuple::empty(py) PyTuple::empty(py)
} }
} }
@ -185,7 +185,7 @@ impl ToPyTuple for NoArgs {
/// Converts `()` to an empty Python tuple. /// Converts `()` to an empty Python tuple.
impl ToPyTuple for () { impl ToPyTuple for () {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> Py<'p, PyTuple> { fn to_py_tuple(&self, py: Token) -> PyPtr<PyTuple> {
PyTuple::empty(py) PyTuple::empty(py)
} }
} }
@ -198,7 +198,7 @@ pyobject_extract!(obj to NoArgs => {
if t.len() == 0 { if t.len() == 0 {
Ok(NoArgs) Ok(NoArgs)
} else { } else {
Err(wrong_tuple_length(obj.py(), t, 0)) Err(wrong_tuple_length(obj.token(), t, 0))
} }
}); });

View file

@ -6,14 +6,14 @@ use std::ffi::CStr;
use std::borrow::Cow; use std::borrow::Cow;
use ffi; use ffi;
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::{AsPy, Python, ToPythonPointer}; use python::{Python, PythonToken, ToPythonPointer, Token, PythonObjectWithToken};
use conversion::ToPyTuple; use conversion::ToPyTuple;
use objects::{PyObject, PyDict}; use objects::{PyObject, PyDict};
use err::PyResult; use err::PyResult;
/// Represents a reference to a Python type object. /// Represents a reference to a Python type object.
pub struct PyType; pub struct PyType(PythonToken<PyType>);
pyobject_newtype!(PyType, PyType_Check, PyType_Type); pyobject_newtype!(PyType, PyType_Check, PyType_Type);
@ -28,8 +28,8 @@ impl PyType {
/// This increments the reference count on the type object. /// This increments the reference count on the type object.
/// Undefined behavior if the pointer is NULL or invalid. /// Undefined behavior if the pointer is NULL or invalid.
#[inline] #[inline]
pub unsafe fn from_type_ptr(py: Python, p: *mut ffi::PyTypeObject) -> Py<PyType> { pub unsafe fn from_type_ptr(_py: Token, p: *mut ffi::PyTypeObject) -> PyPtr<PyType> {
Py::from_borrowed_ptr(py, p as *mut ffi::PyObject) PyPtr::from_borrowed_ptr(p as *mut ffi::PyObject)
} }
/// Gets the name of the PyType. /// Gets the name of the PyType.
@ -54,13 +54,13 @@ impl PyType {
// /// Calls the type object, thus creating a new instance. // /// Calls the type object, thus creating a new instance.
// /// This is equivalent to the Python expression: `self(*args, **kwargs)` // /// This is equivalent to the Python expression: `self(*args, **kwargs)`
#[inline] #[inline]
pub fn call<'p, A>(&'p self, args: A, kwargs: Option<&PyDict>) -> PyResult<Py<'p, PyObject>> pub fn call<'p, A>(&'p self, args: A, kwargs: Option<&PyDict>) -> PyResult<PyPtr<PyObject>>
where A: ToPyTuple where A: ToPyTuple
{ {
let args = args.to_py_tuple(self.py()); let args = args.to_py_tuple(self.token());
unsafe { unsafe {
Py::from_owned_ptr_or_err( PyPtr::from_owned_ptr_or_err(
self.py(), ffi::PyObject_Call(self.as_ptr(), args.as_ptr(), kwargs.as_ptr())) self.token(), ffi::PyObject_Call(self.as_ptr(), args.as_ptr(), kwargs.as_ptr()))
} }
} }
} }

View file

@ -8,7 +8,7 @@ use std::convert::{AsRef, AsMut};
use ffi; use ffi;
use err::{PyErr, PyResult, PyDowncastError}; use err::{PyErr, PyResult, PyDowncastError};
use conversion::{ToPyObject, IntoPyObject}; use conversion::{ToPyObject, IntoPyObject};
use python::{AsPy, Python, ToPythonPointer, IntoPythonPointer}; use python::{Python, ToPythonPointer, IntoPythonPointer, Token, PythonObjectWithToken};
use objects::PyObject; use objects::PyObject;
use typeob::{PyTypeInfo, PyObjectAlloc}; use typeob::{PyTypeInfo, PyObjectAlloc};
@ -29,10 +29,34 @@ impl<T> PyPtr<T> {
PyPtr {inner: ptr, _t: PhantomData} PyPtr {inner: ptr, _t: PhantomData}
} }
/// Creates a PyPTr instance for the given FFI pointer. /// 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`.
/// Unsafe because the pointer might be invalid.
pub unsafe fn from_owned_ptr_or_err(py: Token, ptr: *mut ffi::PyObject) -> PyResult<PyPtr<T>>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(PyPtr::from_owned_ptr(ptr))
}
}
/// Cast from ffi::PyObject ptr to PyPtr pointer
#[inline]
pub unsafe fn from_owned_ptr_or_panic(ptr: *mut ffi::PyObject) -> PyPtr<T>
{
if ptr.is_null() {
::err::panic_after_error();
} else {
PyPtr::from_owned_ptr(ptr)
}
}
/// Creates a PyPtr instance for the given FFI pointer.
/// Calls Py_INCREF() on the ptr. /// Calls Py_INCREF() on the ptr.
/// Undefined behavior if the pointer is NULL or invalid. /// Undefined behavior if the pointer is NULL or invalid.
/// Caller of this method has to have valid Py object. /// Caller of this method has to have valid Python object.
#[inline] #[inline]
pub unsafe fn from_borrowed_ptr(ptr: *mut ffi::PyObject) -> PyPtr<T> { pub unsafe fn from_borrowed_ptr(ptr: *mut ffi::PyObject) -> PyPtr<T> {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
@ -40,12 +64,35 @@ impl<T> PyPtr<T> {
PyPtr {inner: ptr, _t: PhantomData} PyPtr {inner: ptr, _t: PhantomData}
} }
pub fn as_ref<'p>(&self, _py: Python<'p>) -> Py<'p, T> { /// Creates a Py instance for the given FFI pointer.
Py{inner: self.inner, _t: PhantomData, _py: PhantomData} /// Calls Py_INCREF() on the ptr.
#[inline]
pub unsafe fn from_borrowed_ptr_opt(_py: Token,
ptr: *mut ffi::PyObject) -> Option<PyPtr<T>> {
if ptr.is_null() {
None
} else {
debug_assert!(ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr);
Some(PyPtr{inner: ptr, _t: PhantomData})
}
} }
pub fn into_ref<'p>(self, _py: Python<'p>) -> Py<'p, T> { pub fn as_ref<'p>(&self, py: Token<'p>) -> Py<'p, T> {
let p = Py{inner: self.inner, _t: PhantomData, _py: PhantomData}; unsafe { Py::from_borrowed_ptr(py, self.inner) }
}
pub fn into_ref<'p>(self, py: Token<'p>) -> Py<'p, T> {
let p = Py{inner: self.inner, _t: PhantomData, py: py};
std::mem::forget(self);
p
}
/// Converts PyPtr<T> -> PyPtr<PyObject>
/// Consumes `self` without calling `Py_INCREF()`
#[inline]
pub fn into_object(self) -> PyPtr<PyObject> {
let p = PyPtr {inner: self.inner, _t: PhantomData};
std::mem::forget(self); std::mem::forget(self);
p p
} }
@ -57,9 +104,19 @@ impl<T> PyPtr<T> {
} }
#[inline] #[inline]
pub fn clone_ref(&self, _py: Python) -> PyPtr<T> { pub fn clone_ref(&self) -> PyPtr<T> {
PyPtr{inner: self.inner.clone(), _t: PhantomData} PyPtr{inner: self.inner.clone(), _t: PhantomData}
} }
/// Unchecked downcast from other PyPtr<S> to PyPtr<S>.
/// Undefined behavior if the input object does not have the expected type.
#[inline]
pub unsafe fn unchecked_downcast_from<S>(py: PyPtr<S>) -> PyPtr<T>
{
let res = PyPtr {inner: py.inner, _t: PhantomData};
std::mem::forget(py);
res
}
} }
impl<T> ToPythonPointer for PyPtr<T> { impl<T> ToPythonPointer for PyPtr<T> {
@ -85,8 +142,8 @@ impl<T> IntoPythonPointer for PyPtr<T> {
impl<T> IntoPyObject for PyPtr<T> { impl<T> IntoPyObject for PyPtr<T> {
#[inline] #[inline]
fn into_object<'a>(self, py: Python<'a>) -> Py<'a, PyObject> { fn into_object<'a>(self, py: Token) -> PyPtr<PyObject> {
self.into_ref(py).into_object() self.into_object()
} }
} }
@ -111,7 +168,7 @@ impl<T> Drop for PyPtr<T> {
pub struct Py<'p, T> { pub struct Py<'p, T> {
pub inner: *mut ffi::PyObject, pub inner: *mut ffi::PyObject,
_t: PhantomData<T>, _t: PhantomData<T>,
_py: PhantomData<Python<'p>>, py: Token<'p>,
} }
impl<'p, T> Py<'p, T> impl<'p, T> Py<'p, T>
@ -120,17 +177,17 @@ impl<'p, T> Py<'p, T>
/// This moves ownership over the pointer into the Py. /// This moves ownership over the pointer into the Py.
/// Undefined behavior if the pointer is NULL or invalid. /// Undefined behavior if the pointer is NULL or invalid.
#[inline] #[inline]
pub unsafe fn from_owned_ptr(_py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> { pub unsafe fn from_owned_ptr(py: Token<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
Py {inner: ptr, _t: PhantomData, _py: PhantomData} Py {inner: ptr, _t: PhantomData, py: py}
} }
/// Cast from ffi::PyObject ptr to a concrete object. /// Cast from ffi::PyObject ptr to a concrete object.
#[inline] #[inline]
pub unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> pub unsafe fn from_owned_ptr_or_panic(py: Token<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T>
{ {
if ptr.is_null() { if ptr.is_null() {
::err::panic_after_error(py); ::err::panic_after_error();
} else { } else {
Py::from_owned_ptr(py, ptr) Py::from_owned_ptr(py, ptr)
} }
@ -140,7 +197,7 @@ impl<'p, T> Py<'p, T>
/// returns a new reference (owned pointer). /// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is `null`. /// Returns `Err(PyErr)` if the pointer is `null`.
/// Unsafe because the pointer might be invalid. /// Unsafe because the pointer might be invalid.
pub unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) pub unsafe fn from_owned_ptr_or_err(py: Token<'p>, ptr: *mut ffi::PyObject)
-> PyResult<Py<'p, T>> -> PyResult<Py<'p, T>>
{ {
if ptr.is_null() { if ptr.is_null() {
@ -154,33 +211,26 @@ impl<'p, T> Py<'p, T>
/// Calls Py_INCREF() on the ptr. /// Calls Py_INCREF() on the ptr.
/// Undefined behavior if the pointer is NULL or invalid. /// Undefined behavior if the pointer is NULL or invalid.
#[inline] #[inline]
pub unsafe fn from_borrowed_ptr(_py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> { pub unsafe fn from_borrowed_ptr(py: Token<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr); ffi::Py_INCREF(ptr);
Py {inner: ptr, _t: PhantomData, _py: PhantomData} Py {inner: ptr, _t: PhantomData, py: py}
} }
/// Creates a Py instance for the given FFI pointer. /// Creates a Py instance for the given FFI pointer.
/// Calls Py_INCREF() on the ptr. /// Calls Py_INCREF() on the ptr.
#[inline] #[inline]
pub unsafe fn from_borrowed_ptr_opt(_py: Python<'p>, pub unsafe fn from_borrowed_ptr_opt(py: Token<'p>,
ptr: *mut ffi::PyObject) -> Option<Py<'p, T>> { ptr: *mut ffi::PyObject) -> Option<Py<'p, T>> {
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
debug_assert!(ffi::Py_REFCNT(ptr) > 0); debug_assert!(ffi::Py_REFCNT(ptr) > 0);
ffi::Py_INCREF(ptr); ffi::Py_INCREF(ptr);
Some(Py {inner: ptr, _t: PhantomData, _py: PhantomData}) Some(Py {inner: ptr, _t: PhantomData, py: py})
} }
} }
/// Retrieve Python instance, the GIL is already acquired and
/// stays acquired for the lifetime `'p`.
#[inline]
pub fn py(&self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}
/// Gets the reference count of this Py object. /// Gets the reference count of this Py object.
#[inline] #[inline]
pub fn get_refcnt(&self) -> usize { pub fn get_refcnt(&self) -> usize {
@ -209,24 +259,28 @@ impl<'p, T> Py<'p, T>
/// Consumes `self` without calling `Py_DECREF()` /// Consumes `self` without calling `Py_DECREF()`
#[inline] #[inline]
pub fn into_object(self) -> Py<'p, PyObject> { pub fn into_object(self) -> Py<'p, PyObject> {
let p = Py {inner: self.inner, _t: PhantomData, _py: PhantomData}; let p = Py {inner: self.inner, _t: PhantomData, py: self.py};
std::mem::forget(self); std::mem::forget(self);
p p
} }
/// Unchecked downcast from other Py<S> to Self<T. /// Unchecked downcast from other Py<S> to Py<S>.
/// Undefined behavior if the input object does not have the expected type. /// Undefined behavior if the input object does not have the expected type.
#[inline] #[inline]
pub unsafe fn unchecked_downcast_from<'a, S>(py: Py<'a, S>) -> Py<'a, T> pub unsafe fn unchecked_downcast_from<'a, S>(ob: Py<'a, S>) -> Py<'a, T>
{ {
let res = Py {inner: py.inner, _t: PhantomData, _py: PhantomData}; let res = Py {inner: ob.inner, _t: PhantomData, py: ob.py};
std::mem::forget(py); std::mem::forget(ob);
res res
} }
pub fn clone_ref(&self) -> Py<'p, T> { pub fn clone_ref(&self) -> Py<'p, T> {
unsafe { ffi::Py_INCREF(self.inner) }; unsafe { ffi::Py_INCREF(self.inner) };
Py {inner: self.inner, _t: self._t, _py: self._py} Py {inner: self.inner, _t: self._t, py: self.py}
}
pub fn token<'a>(&'a self) -> Token<'p> {
self.py
} }
} }
@ -234,17 +288,17 @@ impl<'p, T> Py<'p, T>
impl<'p, T> Py<'p, T> where T: PyTypeInfo impl<'p, T> Py<'p, T> where T: PyTypeInfo
{ {
/// Create new python object and move T instance under python management /// Create new python object and move T instance under python management
pub fn new(py: Python<'p>, value: T) -> PyResult<Py<'p, T>> where T: PyObjectAlloc<Type=T> pub fn new(py: Token<'p>, value: T) -> PyResult<Py<'p, T>> where T: PyObjectAlloc<Type=T>
{ {
let ob = unsafe { let ob = unsafe {
try!(<T as PyObjectAlloc>::alloc(py, value)) try!(<T as PyObjectAlloc>::alloc(py, value))
}; };
Ok(Py{inner: ob, _t: PhantomData, _py: PhantomData}) Ok(Py{inner: ob, _t: PhantomData, py: py})
} }
/// Cast from ffi::PyObject ptr to a concrete object. /// Cast from ffi::PyObject ptr to a concrete object.
#[inline] #[inline]
pub fn cast_from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) pub fn cast_from_borrowed_ptr(py: Token<'p>, ptr: *mut ffi::PyObject)
-> Result<Py<'p, T>, ::PyDowncastError<'p>> -> Result<Py<'p, T>, ::PyDowncastError<'p>>
{ {
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 }; let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 };
@ -258,7 +312,7 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
/// Cast from ffi::PyObject ptr to a concrete object. /// Cast from ffi::PyObject ptr to a concrete object.
#[inline] #[inline]
pub fn cast_from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) pub fn cast_from_owned_ptr(py: Token<'p>, ptr: *mut ffi::PyObject)
-> Result<Py<'p, T>, ::PyDowncastError<'p>> -> Result<Py<'p, T>, ::PyDowncastError<'p>>
{ {
let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 }; let checked = unsafe { ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 };
@ -272,17 +326,17 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
/// Cast from ffi::PyObject ptr to a concrete object. /// Cast from ffi::PyObject ptr to a concrete object.
#[inline] #[inline]
pub unsafe fn cast_from_owned_ptr_or_panic(py: Python<'p>, pub unsafe fn cast_from_owned_ptr_or_panic(py: Token<'p>,
ptr: *mut ffi::PyObject) -> Py<'p, T> ptr: *mut ffi::PyObject) -> Py<'p, T>
{ {
if ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 { if ffi::PyObject_TypeCheck(ptr, T::type_object()) != 0 {
Py::from_owned_ptr(py, ptr) Py::from_owned_ptr(py, ptr)
} else { } else {
::err::panic_after_error(py); ::err::panic_after_error();
} }
} }
pub fn cast_from_owned_nullptr(py: Python<'p>, ptr: *mut ffi::PyObject) pub fn cast_from_owned_nullptr(py: Token<'p>, ptr: *mut ffi::PyObject)
-> PyResult<Py<'p, T>> -> PyResult<Py<'p, T>>
{ {
if ptr.is_null() { if ptr.is_null() {
@ -322,7 +376,7 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
if checked { if checked {
Ok( unsafe { Py::<D>::unchecked_downcast_from(self.clone_ref()) }) Ok( unsafe { Py::<D>::unchecked_downcast_from(self.clone_ref()) })
} else { } else {
Err(PyDowncastError(self.py(), None)) Err(PyDowncastError(self.py, None))
} }
} }
@ -330,13 +384,13 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
/// Fails with `PyDowncastError` if the object is not of the expected type. /// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline] #[inline]
pub fn cast_into<D>(self) -> Result<Py<'p, D>, PyDowncastError<'p>> pub fn cast_into<D>(self) -> Result<Py<'p, D>, PyDowncastError<'p>>
where D: PyTypeInfo where D: 'p + PyTypeInfo
{ {
let checked = unsafe { ffi::PyObject_TypeCheck(self.inner, D::type_object()) != 0 }; let checked = unsafe { ffi::PyObject_TypeCheck(self.inner, D::type_object()) != 0 };
if checked { if checked {
Ok( unsafe { Py::<D>::unchecked_downcast_from(self) }) Ok( unsafe { Py::<D>::unchecked_downcast_from(self) })
} else { } else {
Err(PyDowncastError(self.py(), None)) Err(PyDowncastError(self.py, None))
} }
} }
@ -355,7 +409,7 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
let ptr = (self.inner as *mut u8).offset(offset) as *mut D; let ptr = (self.inner as *mut u8).offset(offset) as *mut D;
ptr.as_ref().unwrap() }) ptr.as_ref().unwrap() })
} else { } else {
Err(PyDowncastError(self.py(), None)) Err(PyDowncastError(self.token(), None))
} }
} }
@ -378,14 +432,11 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
} }
} }
impl<'p, T> AsPy<'p> for Py<'p, T> { //impl<'p, T> PythonObjectWithToken for Py<'p, T> {
/// Retrieve Python instance, the GIL is already acquired and // fn token(&self) -> Token {
/// stays acquired for the lifetime `'p`. // self.py.token()
#[inline] // }
fn py<'a>(&'a self) -> Python<'p> { //}
unsafe { Python::assume_gil_acquired() }
}
}
impl<'p, T> ToPythonPointer for Py<'p, T> { impl<'p, T> ToPythonPointer for Py<'p, T> {
/// Gets the underlying FFI pointer, returns a borrowed pointer. /// Gets the underlying FFI pointer, returns a borrowed pointer.
@ -412,7 +463,9 @@ impl<'p, T> IntoPythonPointer for Py<'p, T> {
impl<'p, T> Drop for Py<'p, T> { impl<'p, T> Drop for Py<'p, T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
println!("drop Py: {:?} {}", self.inner, ffi::Py_REFCNT(self.inner)); println!("drop Py: {:?} {} {:?}",
self.inner,
ffi::Py_REFCNT(self.inner), &self as *const _);
} }
unsafe { ffi::Py_DECREF(self.inner); } unsafe { ffi::Py_DECREF(self.inner); }
} }
@ -423,7 +476,7 @@ impl<'p, T> Clone for Py<'p, T> {
unsafe { unsafe {
debug_assert!(!self.inner.is_null() && ffi::Py_REFCNT(self.inner) > 0); debug_assert!(!self.inner.is_null() && ffi::Py_REFCNT(self.inner) > 0);
ffi::Py_INCREF(self.inner); ffi::Py_INCREF(self.inner);
Py {inner: self.inner, _t: PhantomData, _py: PhantomData} Py {inner: self.inner, _t: PhantomData, py: self.py}
} }
} }
} }
@ -476,9 +529,9 @@ impl<'source, T> ::FromPyObject<'source> for Py<'source, T> where T: PyTypeInfo
{ {
let checked = unsafe { ffi::PyObject_TypeCheck(py.inner, T::type_object()) != 0 }; let checked = unsafe { ffi::PyObject_TypeCheck(py.inner, T::type_object()) != 0 };
if checked { if checked {
Ok( unsafe { Py::<T>::from_borrowed_ptr(py.py(), py.as_ptr()) }) Ok( unsafe { Py::<T>::from_borrowed_ptr(py.token(), py.as_ptr()) })
} else { } else {
Err(PyDowncastError(py.py(), None).into()) Err(PyDowncastError(py.token(), None).into())
} }
} }
} }
@ -486,12 +539,27 @@ impl<'source, T> ::FromPyObject<'source> for Py<'source, T> where T: PyTypeInfo
impl <'a, T> ToPyObject for Py<'a, T> { impl <'a, T> ToPyObject for Py<'a, T> {
#[inline] #[inline]
default fn to_object<'p>(&self, py: Python<'p>) -> Py<'p, PyObject> { default fn to_object<'p>(&self, py: Token) -> PyPtr<PyObject> {
PyObject::from_owned_ptr(py, self.inner) unsafe { PyPtr::from_borrowed_ptr(self.inner) }
} }
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R fn with_borrowed_ptr<F, R>(&self, py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
f(self.inner)
}
}
impl<T> ToPyObject for PyPtr<T> {
#[inline]
default fn to_object(&self, py: Token) -> PyPtr<PyObject> {
unsafe { PyPtr::from_borrowed_ptr(self.inner) }
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Token, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R where F: FnOnce(*mut ffi::PyObject) -> R
{ {
f(self.inner) f(self.inner)
@ -501,8 +569,10 @@ impl <'a, T> ToPyObject for Py<'a, T> {
impl<'p, T> IntoPyObject for Py<'p, T> { impl<'p, T> IntoPyObject for Py<'p, T> {
#[inline] #[inline]
default fn into_object<'a>(self, py: Python<'a>) -> Py<'a, PyObject> { default fn into_object(self, py: Token) -> PyPtr<PyObject> {
PyObject::from_borrowed_ptr(py, self.inner) let ptr = unsafe { PyPtr::from_owned_ptr(self.inner) };
std::mem::forget(self);
ptr
} }
} }

View file

@ -28,23 +28,46 @@ use pythonrun::GILGuard;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Python<'p>(PhantomData<&'p GILGuard>); pub struct Python<'p>(PhantomData<&'p GILGuard>);
#[derive(Copy, Clone)]
pub struct Token<'p>(PhantomData<&'p GILGuard>);
pub struct PythonToken<T>(PhantomData<T>); pub struct PythonToken<T>(PhantomData<T>);
pub trait AsPy<'p> { pub trait PythonObjectWithToken : Sized {
fn py<'a>(&'a self) -> Python<'p>; fn token<'p>(&'p self) -> Token<'p>;
} }
pub trait PyClone : Sized { pub trait PyClone : Sized {
fn clone_ref(&self) -> PyPtr<Self>; fn clone_ref(&self) -> PyPtr<Self>;
} }
impl<T> PyClone for T where T: ToPythonPointer {
#[inline]
fn clone_ref(&self) -> PyPtr<T> {
unsafe {
let ptr = <T as ToPythonPointer>::as_ptr(self);
PyPtr::from_borrowed_ptr(ptr)
}
}
}
/// This trait allows retrieving the underlying FFI pointer from Python objects. /// This trait allows retrieving the underlying FFI pointer from Python objects.
pub trait ToPythonPointer { pub trait ToPythonPointer {
/// Retrieves the underlying FFI pointer (as a borrowed pointer). /// Retrieves the underlying FFI pointer (as a borrowed pointer).
fn as_ptr(&self) -> *mut ffi::PyObject; fn as_ptr(&self) -> *mut ffi::PyObject;
}
impl<'p, T> ToPythonPointer for T where T: PyTypeInfo + PythonObjectWithToken {
#[inline]
default fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <T as PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut ffi::PyObject
}
}
} }
/// This trait allows retrieving the underlying FFI pointer from Python objects. /// This trait allows retrieving the underlying FFI pointer from Python objects.
@ -56,7 +79,18 @@ pub trait IntoPythonPointer {
/// Convert None into a null pointer. /// Convert None into a null pointer.
impl <T> ToPythonPointer for Option<T> where T: ToPythonPointer { /*impl <T> ToPythonPointer for Option<T> where T: ToPythonPointer {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
match *self {
Some(ref t) => t.as_ptr(),
None => std::ptr::null_mut()
}
}
}*/
/// Convert None into a null pointer.
impl<'p, T> ToPythonPointer for Option<&'p T> where T: ToPythonPointer {
#[inline] #[inline]
fn as_ptr(&self) -> *mut ffi::PyObject { fn as_ptr(&self) -> *mut ffi::PyObject {
match *self { match *self {
@ -116,7 +150,7 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`. /// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`. /// If `locals` is `None`, it defaults to the value of `globals`.
pub fn eval(self, code: &str, globals: Option<&PyDict>, pub fn eval(self, code: &str, globals: Option<&PyDict>,
locals: Option<&PyDict>) -> PyResult<Py<'p, PyObject>> { locals: Option<&PyDict>) -> PyResult<PyPtr<PyObject>> {
self.run_code(code, ffi::Py_eval_input, globals, locals) self.run_code(code, ffi::Py_eval_input, globals, locals)
} }
@ -137,13 +171,13 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`. /// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`. /// If `locals` is `None`, it defaults to the value of `globals`.
fn run_code(self, code: &str, start: c_int, fn run_code(self, code: &str, start: c_int,
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<Py<'p, PyObject>> { globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<PyPtr<PyObject>> {
let code = CString::new(code).unwrap(); let code = CString::new(code).unwrap();
unsafe { unsafe {
let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _);
if mptr.is_null() { if mptr.is_null() {
return Err(PyErr::fetch(self)); return Err(PyErr::fetch(self.token()));
} }
let mdict = ffi::PyModule_GetDict(mptr); let mdict = ffi::PyModule_GetDict(mptr);
@ -161,75 +195,58 @@ impl<'p> Python<'p> {
let res_ptr = ffi::PyRun_StringFlags(code.as_ptr(), let res_ptr = ffi::PyRun_StringFlags(code.as_ptr(),
start, globals, locals, 0 as *mut _); start, globals, locals, 0 as *mut _);
Py::from_owned_ptr_or_err(self, res_ptr) PyPtr::from_owned_ptr_or_err(self.token(), res_ptr)
} }
} }
/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn None(self) -> Py<'p, PyObject> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_None()) }
}
/// Gets the Python builtin value `True`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn True(self) -> Py<'p, PyBool> {
unsafe { Py::from_borrowed_ptr(self, ffi::Py_True()) }
}
/// Gets the Python builtin value `False`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn False(self) -> Py<'p, PyBool> {
unsafe { Py::from_borrowed_ptr(self, ffi::Py_False()) }
}
/// Gets the Python builtin value `NotImplemented`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn NotImplemented(self) -> Py<'p, PyObject> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_NotImplemented()) }
}
/// Gets the Python type object for type T. /// Gets the Python type object for type T.
pub fn get_type<T>(self) -> Py<'p, PyType> where T: PyTypeObject { pub fn get_type<T>(self) -> PyPtr<PyType> where T: PyTypeObject {
T::type_object(self) T::type_object(self.token())
}
/// Gets the Python type object for type T.
pub fn get_ptype<T>(self) -> PyPtr<PyType> where T: PyTypeObject {
T::type_object(self).into_pptr()
} }
/// Import the Python module with the specified name. /// 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<Py<'p, PyModule>> {
PyModule::import(self, name) PyModule::import(self.token(), name)
} }
pub fn with_token<T, F>(self, f: F) -> Py<'p, T> pub fn with_token<T, F>(self, f: F) -> PyPtr<T>
where F: FnOnce(PythonToken<T>) -> T, where F: FnOnce(PythonToken<T>) -> T,
T: PyTypeInfo + PyObjectAlloc<Type=T> T: PyTypeInfo + PyObjectAlloc<Type=T>
{ {
let value = f(PythonToken(PhantomData)); let value = f(PythonToken(PhantomData));
Py::new(self, value).unwrap() if let Ok(ob) = Py::new(self.token(), value) {
println!("created: {:?}", &ob as *const _);
ob.into_pptr()
} else {
::err::panic_after_error()
}
}
//}
//impl<'p> PythonObjectWithToken<'p> for Python<'p> {
pub fn token(self) -> Token<'p> {
Token(PhantomData)
} }
} }
impl<T> PythonToken<T> { impl<T> PythonToken<T> {
pub fn token(&self) -> Token {
Token(PhantomData)
}
}
impl<'p> Token<'p> {
/// Gets the Python builtin value `None`. /// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase #[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline] #[inline]
pub fn None(&self) -> PyPtr<PyObject> { pub fn None(self) -> PyPtr<PyObject> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_None()) } unsafe { PyPtr::from_borrowed_ptr(ffi::Py_None()) }
} }
/// Gets the Python builtin value `True`. /// Gets the Python builtin value `True`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase #[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline] #[inline]
pub fn True(&self) -> PyPtr<PyBool> { pub fn True(self) -> PyPtr<PyBool> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_True()) } unsafe { PyPtr::from_borrowed_ptr(ffi::Py_True()) }
} }
@ -243,32 +260,51 @@ impl<T> PythonToken<T> {
/// Gets the Python builtin value `NotImplemented`. /// Gets the Python builtin value `NotImplemented`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase #[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline] #[inline]
pub fn NotImplemented(&self) -> PyPtr<PyObject> { pub fn NotImplemented(self) -> PyPtr<PyObject> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_NotImplemented()) } unsafe { PyPtr::from_borrowed_ptr(ffi::Py_NotImplemented()) }
} }
/// Gets the Python type object for type T. /// Gets the Python type object for type T.
pub fn get_type<U>(&self) -> PyPtr<PyType> where U: PyTypeObject { #[inline]
U::type_object(Python(PhantomData)).into_pptr() pub fn get_type<U>(self) -> PyPtr<PyType> where U: PyTypeObject {
U::type_object(self)
} }
/// Execute closure `F` with Python instance. /// Execute closure `F` with Python instance.
/// Retrieve Python instance under the assumption that the GIL is already acquired /// Retrieve Python instance under the assumption that the GIL is already acquired
/// at this point, and stays acquired during closure call. /// at this point, and stays acquired during closure call.
pub fn with<'p, F>(&self, f: F) where F: FnOnce(Python<'p>) pub fn with<F, R>(self, f: F) -> R where F: FnOnce(Python<'p>) -> R
{ {
f(Python(PhantomData)) f(Python(PhantomData))
} }
pub fn with_token<P, F>(&self, f: F) -> PyPtr<P> /// Convert raw pointer into referece
where F: FnOnce(PythonToken<P>) -> P, #[inline]
P: PyTypeInfo + PyObjectAlloc<Type=P> pub unsafe fn from_owned_ptr<P>(self, ptr: *mut ffi::PyObject) -> &'p P
{ {
let value = f(PythonToken(PhantomData)); std::mem::transmute(ptr)
Py::new(Python(PhantomData), value).unwrap().into_pptr() }
#[inline]
pub unsafe fn from_owned_ptr_opt<P>(self, ptr: *mut ffi::PyObject) -> Option<&'p P>
{
if ptr.is_null() {
None
} else {
Some(std::mem::transmute(ptr))
} }
} }
#[inline]
pub unsafe fn from_owned_ptr_or_panic<P>(self, ptr: *mut ffi::PyObject) -> &'p P
{
if ptr.is_null() {
::err::panic_after_error();
} else {
std::mem::transmute(ptr)
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View file

@ -7,8 +7,8 @@ use std::collections::HashMap;
use {ffi, class}; use {ffi, class};
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use pyptr::Py; use pyptr::{Py, PyPtr};
use python::Python; use python::{Python, PythonObjectWithToken, Token};
use objects::PyType; use objects::PyType;
use callback::AbortOnDrop; use callback::AbortOnDrop;
use class::methods::PyMethodDefType; use class::methods::PyMethodDefType;
@ -92,12 +92,12 @@ pub trait PyObjectAlloc {
/// and initializes it using init_val. /// and initializes it using init_val.
/// `ty` must be derived from the Self type, and the resulting object /// `ty` must be derived from the Self type, and the resulting object
/// must be of type `ty`. /// must be of type `ty`.
unsafe fn alloc(_py: Python, value: Self::Type) -> PyResult<*mut ffi::PyObject>; unsafe fn alloc(py: Token, value: Self::Type) -> PyResult<*mut ffi::PyObject>;
/// Calls the rust destructor for the object and frees the memory /// Calls the rust destructor for the object and frees the memory
/// (usually by calling ptr->ob_type->tp_free). /// (usually by calling ptr->ob_type->tp_free).
/// This function is used as tp_dealloc implementation. /// This function is used as tp_dealloc implementation.
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject); unsafe fn dealloc(py: Token, obj: *mut ffi::PyObject);
} }
/// A PythonObject that is usable as a base type for #[class] /// A PythonObject that is usable as a base type for #[class]
@ -108,13 +108,16 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// and initializes it using init_val. /// and initializes it using init_val.
/// `ty` must be derived from the Self type, and the resulting object /// `ty` must be derived from the Self type, and the resulting object
/// must be of type `ty`. /// must be of type `ty`.
unsafe fn alloc(_py: Python, value: T::Type) -> PyResult<*mut ffi::PyObject> { unsafe fn alloc(py: Token, value: T::Type) -> PyResult<*mut ffi::PyObject> {
let _ = <T as PyTypeObject>::type_object(_py); let _ = <T as PyTypeObject>::type_object(py);
let obj = ffi::PyType_GenericAlloc( let obj = ffi::PyType_GenericAlloc(
<Self as PyTypeInfo>::type_object(), 0); <Self as PyTypeInfo>::type_object(), 0);
let offset = <Self as PyTypeInfo>::offset(); let offset = <Self as PyTypeInfo>::offset();
println!("alloc {} {:?} {} {}", offset, obj, <Self as PyTypeInfo>::size(),
<Self as PyTypeInfo>::type_object().tp_basicsize);
let ptr = (obj as *mut u8).offset(offset) as *mut Self::Type; let ptr = (obj as *mut u8).offset(offset) as *mut Self::Type;
std::ptr::write(ptr, value); std::ptr::write(ptr, value);
@ -124,7 +127,7 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// Calls the rust destructor for the object and frees the memory /// Calls the rust destructor for the object and frees the memory
/// (usually by calling ptr->ob_type->tp_free). /// (usually by calling ptr->ob_type->tp_free).
/// This function is used as tp_dealloc implementation. /// This function is used as tp_dealloc implementation.
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) { unsafe fn dealloc(py: Token, obj: *mut ffi::PyObject) {
let ptr = (obj as *mut u8).offset( let ptr = (obj as *mut u8).offset(
<Self as PyTypeInfo>::offset() as isize) as *mut Self::Type; <Self as PyTypeInfo>::offset() as isize) as *mut Self::Type;
std::ptr::drop_in_place(ptr); std::ptr::drop_in_place(ptr);
@ -147,14 +150,14 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
pub trait PyTypeObject { pub trait PyTypeObject {
/// Retrieves the type object for this Python object type. /// Retrieves the type object for this Python object type.
fn type_object<'p>(py: Python<'p>) -> Py<'p, PyType>; fn type_object(py: Token) -> PyPtr<PyType>;
} }
impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo { impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
#[inline] #[inline]
fn type_object<'p>(py: Python<'p>) -> Py<'p, PyType> { fn type_object<'p>(py: Token) -> PyPtr<PyType> {
let mut ty = <T as PyTypeInfo>::type_object(); let mut ty = <T as PyTypeInfo>::type_object();
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 { if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
@ -169,10 +172,11 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
} }
} }
pub fn initialize_type<'p, T>(py: Python<'p>, module_name: Option<&str>, type_name: &str, pub fn initialize_type<'p, T>(py: Token, module_name: Option<&str>, type_name: &str,
type_object: &mut ffi::PyTypeObject) -> PyResult<Py<'p, PyType>> type_object: &mut ffi::PyTypeObject) -> PyResult<PyPtr<PyType>>
where T: PyObjectAlloc + PyTypeInfo where T: PyObjectAlloc + PyTypeInfo
{ {
println!("=========== init type");
// type name // type name
let name = match module_name { let name = match module_name {
Some(module_name) => CString::new(format!("{}.{}", module_name, type_name)), Some(module_name) => CString::new(format!("{}.{}", module_name, type_name)),
@ -298,7 +302,7 @@ unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
println!("DEALLOC: {:?}", obj); println!("DEALLOC: {:?}", obj);
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc"); let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let r = <T as PyObjectAlloc>::dealloc(py, obj); let r = <T as PyObjectAlloc>::dealloc(py.token(), obj);
mem::forget(guard); mem::forget(guard);
r r
} }