fix unchecked downcast; added objects pool

This commit is contained in:
Nikolay Kim 2017-06-22 10:26:07 -07:00
parent b9377849c8
commit cb969161c6
16 changed files with 163 additions and 136 deletions

View File

@ -45,41 +45,37 @@ pub fn py3_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
pub unsafe extern "C" fn #cb_name() -> *mut ::pyo3::ffi::PyObject {
use std;
extern crate pyo3 as _pyo3;
use pyo3::IntoPyPointer;
use pyo3::{IntoPyPointer, ObjectProtocol};
static mut MODULE_DEF: _pyo3::ffi::PyModuleDef = _pyo3::ffi::PyModuleDef_INIT;
// We can't convert &'static str to *const c_char within a static initializer,
// so we'll do it here in the module initialization:
MODULE_DEF.m_name = concat!(stringify!(#cb_name), "\0").as_ptr() as *const _;
let guard = _pyo3::callback::AbortOnDrop("py_module_init");
let py = _pyo3::Python::assume_gil_acquired();
_pyo3::ffi::PyEval_InitThreads();
_pyo3::callback::cb_meth("py_module_init", |py| {
_pyo3::ffi::PyEval_InitThreads();
let module = _pyo3::ffi::PyModule_Create(&mut MODULE_DEF);
if module.is_null() {
std::mem::forget(guard);
return module;
}
let module = _pyo3::ffi::PyModule_Create(&mut MODULE_DEF);
if module.is_null() {
return module;
}
let module = match py.unchecked_cast_from_ptr_or_err::<PyModule>(module) {
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
std::mem::forget(guard);
return std::ptr::null_mut();
let module = match py.cast_from_ptr_or_err::<_pyo3::PyModule>(module) {
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
return std::ptr::null_mut();
}
};
module.add("__doc__", #doc).expect("Failed to add doc for module");
match #fnname(py, module) {
Ok(_) => module.into_ptr(),
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
}
};
module.add("__doc__", #doc).expect("Failed to add doc for module");
let result = match #fnname(py, module) {
Ok(_) => module.into_ptr(),
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
};
std::mem::forget(guard);
result
})
}
}
}
@ -132,7 +128,7 @@ pub fn py2_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
return
}
let module = match py.unchecked_cast_from_ptr_or_err::<_pyo3::PyModule>(module) {
let module = match py.cast_from_ptr_or_err::<_pyo3::PyModule>(module) {
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
@ -278,7 +274,7 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
};
unsafe {
let func = pyo3::PyObject::from_owned_ptr_or_panic(
let func = pyo3::PyObjectPtr::from_owned_ptr_or_panic(
py, pyo3::ffi::PyCFunction_New(
Box::into_raw(Box::new(def.as_method_def())),
std::ptr::null_mut()));
@ -320,16 +316,16 @@ pub fn impl_wrap(name: &syn::Ident, spec: &method::FnSpec) -> Tokens {
args: *mut _pyo3::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
{
use pyo3::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
#body
};
py.release(args);
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
})

View File

@ -221,13 +221,13 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
unsafe fn unchecked_downcast_from(ob: &_pyo3::PyObject) -> &Self
{
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (ob.as_ptr() as *mut u8).offset(-offset) as *mut #cls;
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
std::mem::transmute(ptr)
}
unsafe fn unchecked_mut_downcast_from(ob: &_pyo3::PyObject) -> &mut Self
{
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (ob.as_ptr() as *mut u8).offset(-offset) as *mut #cls;
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
std::mem::transmute(ptr)
}
}

View File

@ -4,6 +4,7 @@ use std::os::raw::c_int;
use std::{any, mem, ptr, isize, io, panic};
use libc;
use pythonrun;
use python::{Python, IntoPyPointer};
use objects::exc;
use conversion::IntoPyObject;
@ -170,6 +171,7 @@ pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
match f(py) {
@ -189,6 +191,7 @@ pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -202,6 +205,7 @@ pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let slf = Py::<Slf>::from_borrowed_ptr(slf);
@ -225,6 +229,7 @@ pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -236,6 +241,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
Slf: PyTypeInfo,
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let slf = Py::<Slf>::from_borrowed_ptr(slf);
@ -251,6 +257,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
-1
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -260,6 +267,7 @@ pub unsafe fn cb_meth<F>(location: &str, f: F) -> *mut ffi::PyObject
F: panic::UnwindSafe
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -271,6 +279,7 @@ pub unsafe fn cb_meth<F>(location: &str, f: F) -> *mut ffi::PyObject
ptr::null_mut()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -281,6 +290,7 @@ pub unsafe fn cb_pyfunc<F, C, T>(location: &str, _c: C, f: F) -> C::R
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -292,6 +302,7 @@ pub unsafe fn cb_pyfunc<F, C, T>(location: &str, _c: C, f: F) -> C::R
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -301,6 +312,7 @@ pub unsafe fn cb_setter<F>(location: &str, f: F) -> c_int
F: panic::UnwindSafe
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -312,6 +324,7 @@ pub unsafe fn cb_setter<F>(location: &str, f: F) -> c_int
-1
}
};
drop(pool);
mem::forget(guard);
ret
}

View File

@ -11,6 +11,7 @@ use std::os::raw::c_int;
use ::CompareOp;
use ffi;
use callback;
use err::{PyErr, PyResult};
use python::{Python, IntoPyPointer};
use pointer::PyObjectPtr;
@ -366,9 +367,7 @@ impl<T> PyObjectRichcmpProtocolImpl for T
{
const LOCATION: &'static str = concat!(stringify!(T), ".__richcmp__()");
let guard = ::callback::AbortOnDrop(LOCATION);
let ret = std::panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
callback::cb_meth(LOCATION, |py| {
let slf = Py::<T>::from_borrowed_ptr(slf);
let arg = PyObjectPtr::from_borrowed_ptr(py, arg);
@ -397,17 +396,7 @@ impl<T> PyObjectRichcmpProtocolImpl for T
py.release(arg);
py.release(slf);
result
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
::callback::handle_panic(Python::assume_gil_acquired(), err);
std::ptr::null_mut()
}
};
std::mem::forget(guard);
ret
})
}
Some(wrap::<T>)
}

View File

@ -3,13 +3,11 @@
//! Python GC support
//!
use std::mem;
use std::os::raw::{c_int, c_void};
use ffi;
use callback;
use python::{Python, ToPyPointer};
use callback::AbortOnDrop;
use instance::{Py, AsPyRef};
use typeob::PyTypeInfo;
pub struct PyTraverseError(c_int);
@ -97,17 +95,13 @@ impl<T> PyGCTraverseProtocolImpl for T where T: for<'p> PyGCTraverseProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".__traverse__()");
let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired();
let visit = PyVisit { visit: visit, arg: arg, _py: py };
let slf = Py::<T>::from_borrowed_ptr(slf);
let ret = match slf.as_ref(py).__traverse__(py, visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code
};
mem::forget(guard);
ret
callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
let visit = PyVisit { visit: visit, arg: arg, _py: py };
match slf.__traverse__(py, visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code
}
})
}
Some(tp_traverse::<T>)
@ -136,12 +130,10 @@ impl<T> PyGCClearProtocolImpl for T where T: for<'p> PyGCClearProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".__clear__()");
let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired();
let slf = Py::<T>::from_borrowed_ptr(slf);
T::__clear__(&mut slf.as_mut(py), py);
mem::forget(guard);
0
callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
slf.__clear__(py);
0
})
}
Some(tp_clear::<T>)
}

View File

@ -73,13 +73,13 @@ pub trait FromPyObject<'source> : Sized {
fn extract(ob: &'source PyObject) -> PyResult<Self>;
}
/*pub trait RefFromPyObject {
pub trait RefFromPyObject {
fn with_extracted<F, R>(ob: &PyObject, f: F) -> PyResult<R>
where F: FnOnce(&Self) -> R;
}
impl <T: ?Sized> RefFromPyObject for T
where for<'a> &'a T: FromPyObject + Sized
where for<'a> &'a T: FromPyObject<'a> + Sized
{
#[inline]
fn with_extracted<F, R>(obj: &PyObject, f: F) -> PyResult<R>
@ -90,11 +90,10 @@ impl <T: ?Sized> RefFromPyObject for T
Err(e) => Err(e)
}
}
}*/
}
/// Identity conversion: allows using existing `PyObject` instances where
/// `T: ToPyObject` is expected.
// `ToPyObject` for references
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
#[inline]

View File

@ -34,7 +34,7 @@
//! ```rust
//! extern crate pyo3;
//!
//! use pyo3::{Python, PyDict, PyResult};
//! use pyo3::{Python, PyDict, PyResult, ObjectProtocol};
//!
//! fn main() {
//! let gil = Python::acquire_gil();
@ -43,11 +43,11 @@
//!
//! fn hello(py: Python) -> PyResult<()> {
//! let sys = py.import("sys")?;
//! let version: String = sys.get("version")?.extract(py)?;
//! let version: String = sys.get("version")?.extract()?;
//!
//! let locals = PyDict::new(py);
//! locals.set_item("os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(locals))?.extract(py)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(locals))?.extract()?;
//!
//! println!("Hello {}, I'm Python {}", user, version);
//! Ok(())
@ -81,7 +81,7 @@
//! #![feature(proc_macro, specialization)]
//!
//! extern crate pyo3;
//! use pyo3::{py, Python, PyResult, PyObject, PyModule, PyString};
//! use pyo3::{py, Python, PyResult, PyModule, PyString};
//!
//! // add bindings to the generated python module
//! // N.B: names: "libhello" must be the name of the `.so` or `.pyd` file

View File

@ -8,11 +8,11 @@ extern crate num_traits;
use self::num_traits::cast::cast;
use ffi;
use objects::exc;
use pointer::PyObjectPtr;
use python::{ToPyPointer, IntoPyPointer, Python};
use err::{PyResult, PyErr};
use instance::Py;
use instance::{Py, PyObjectWithToken};
use objects::{exc, PyObject};
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// Represents a Python `int` object.
@ -25,7 +25,8 @@ use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// with the primitive Rust integer types.
pub struct PyInt(PyObjectPtr);
pyobject_nativetype2!(PyInt, PyInt_Type, PyInt_Check);
pyobject_convert!(PyInt);
pyobject_nativetype!(PyInt, PyInt_Type, PyInt_Check);
/// In Python 2.x, represents a Python `long` object.
/// Both `PyInt` and `PyLong` refer to the same type on Python 3.x.
@ -36,7 +37,8 @@ pyobject_nativetype2!(PyInt, PyInt_Type, PyInt_Check);
/// with the primitive Rust integer types.
pub struct PyLong(PyObjectPtr);
pyobject_nativetype2!(PyLong, PyLong_Type, PyLong_Check);
pyobject_convert!(PyLong);
pyobject_nativetype!(PyLong, PyLong_Type, PyLong_Check);
impl PyInt {
/// Creates a new Python 2.7 `int` object.
@ -79,12 +81,12 @@ macro_rules! int_fits_c_long(
}
pyobject_extract!(py, obj to $rust_type => {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(py) {
return Err(PyErr::fetch(py));
if val == -1 && PyErr::occurred(obj.token()) {
return Err(PyErr::fetch(obj.token()));
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -105,10 +107,10 @@ macro_rules! int_fits_larger_int(
}
}
pyobject_extract!(py, obj to $rust_type => {
let val = try!(obj.extract::<$larger_type>(py));
let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -151,20 +153,22 @@ macro_rules! int_convert_u64_or_i64 (
}
impl <'source> FromPyObject<'source> for $rust_type {
fn extract(py: Python, obj: &'source PyObject) -> PyResult<$rust_type>
fn extract(obj: &'source PyObject) -> PyResult<$rust_type>
{
let ptr = obj.as_ptr();
unsafe {
if ffi::PyLong_Check(ptr) != 0 {
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
err_if_invalid_value(obj.token(), !0, $pylong_as_ull_or_ull(ptr))
} else if ffi::PyInt_Check(ptr) != 0 {
match cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
} else {
let num = PyObjectPtr::from_owned_ptr_or_err(py, ffi::PyNumber_Long(ptr))?;
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.into_ptr()))
let num = PyObjectPtr::from_owned_ptr_or_err(
obj.token(), ffi::PyNumber_Long(ptr))?;
err_if_invalid_value(
obj.token(), !0, $pylong_as_ull_or_ull(num.into_ptr()))
}
}
}

View File

@ -127,18 +127,18 @@ mod test {
assert_eq!(s, py_string.extract::<String>(py).unwrap());
}
/*#[test]
#[test]
fn test_extract_str() {
let gil = Python::acquire_gil();
let py = gil.python();
let s = "Hello Python";
let py_string = s.to_object(py);
let mut called = false;
RefFromPyObject::with_extracted(py, &py_string.into(),
RefFromPyObject::with_extracted(py_string.as_ref(py),
|s2: &str| {
assert_eq!(s, s2);
called = true;
}).unwrap();
assert!(called);
}*/
}
}

View File

@ -10,25 +10,29 @@ use std::os::raw::c_char;
use ffi;
use err::PyResult;
use pointer::PyObject;
use pointer::PyObjectPtr;
use instance::{Py, PyObjectWithToken};
use python::{Python, ToPyPointer};
use objectprotocol::ObjectProtocol;
use super::{PyObject, PyStringData};
/// Represents a Python string.
pub struct PyString(PyObject);
pub struct PyString(PyObjectPtr);
pyobject_nativetype2!(PyString, PyBaseString_Type, PyBaseString_Check);
pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyBaseString_Type, PyBaseString_Check);
/// Represents a Python unicode string.
pub struct PyUnicode(PyObject);
pub struct PyUnicode(PyObjectPtr);
pyobject_nativetype2!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
pyobject_convert!(PyUnicode);
pyobject_nativetype!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
/// Represents a Python byte string. Corresponds to `str` in Python 2
pub struct PyBytes(PyObject);
pub struct PyBytes(PyObjectPtr);
pyobject_nativetype2!(PyBytes, PyBaseString_Type, PyString_Check);
pyobject_convert!(PyBytes);
pyobject_nativetype!(PyBytes, PyBaseString_Type, PyString_Check);
impl PyString {
@ -47,11 +51,10 @@ impl PyString {
}
}
pub fn from_object(py: Python, src: &PyObject,
encoding: &str, errors: &str) -> PyResult<Py<PyString>> {
pub fn from_object(src: &PyObject, encoding: &str, errors: &str) -> PyResult<Py<PyString>> {
unsafe {
Ok(Py::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8))?
)
}
@ -63,10 +66,9 @@ impl PyString {
/// even if the bytes are not valid UTF-8.
/// For unicode strings, returns the underlying representation used by Python.
pub fn data(&self) -> PyStringData {
let ob: &PyObject = self.as_ref();
if let Ok(bytes) = ob.cast_as::<PyBytes>(self.token()) {
if let Ok(bytes) = self.cast_as::<PyBytes>() {
PyStringData::Utf8(bytes.data())
} else if let Ok(unicode) = ob.cast_as::<PyUnicode>(self.token()) {
} else if let Ok(unicode) = self.cast_as::<PyUnicode>() {
unicode.data()
} else {
panic!("PyString is neither `str` nor `unicode`")
@ -133,12 +135,11 @@ impl PyUnicode {
}
}
pub fn from_object(py: Python, src: &PyObject, encoding: &str, errors: &str)
-> PyResult<Py<PyUnicode>>
pub fn from_object(src: &PyObject, encoding: &str, errors: &str) -> PyResult<Py<PyUnicode>>
{
unsafe {
Ok(Py::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?)
@ -190,6 +191,7 @@ impl std::convert::From<Py<PyUnicode>> for Py<PyString> {
#[cfg(test)]
mod test {
use python::Python;
use instance::AsPyRef;
use conversion::{ToPyObject, RefFromPyObject};
#[test]
@ -208,7 +210,7 @@ mod test {
let s = "Hello Python";
let py_string = s.to_object(py);
let mut called = false;
RefFromPyObject::with_extracted(py, &py_string,
RefFromPyObject::with_extracted(py_string.as_ref(py),
|s2: &str| {
assert_eq!(s, s2);
called = true;

View File

@ -5,7 +5,7 @@ use pointer::PyObjectPtr;
use objects::{PyObject, PyString};
use objectprotocol::ObjectProtocol;
use python::Python;
use conversion::{ToPyObject, IntoPyObject}; //, RefFromPyObject};
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject};
/// Converts Rust `str` to Python object.
/// See `PyString::new` for details on the conversion.
@ -69,11 +69,11 @@ pyobject_extract!(py, obj to String => {
s.to_string().map(Cow::into_owned)
});
/*impl RefFromPyObject for str {
impl RefFromPyObject for str {
fn with_extracted<F, R>(obj: &PyObject, f: F) -> PyResult<R>
where F: FnOnce(&str) -> R
{
let s = try!(obj.extract::<Cow<str>>());
Ok(f(&s))
}
}*/
}

View File

@ -280,8 +280,10 @@ impl<'p> Python<'p> {
pub fn checked_cast_as<D>(self, obj: PyObjectPtr) -> Result<&'p D, PyDowncastError<'p>>
where D: PyDowncastFrom
{
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::downcast_from(p)
unsafe {
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::downcast_from(p)
}
}
pub unsafe fn cast_as<D>(self, obj: PyObjectPtr) -> &'p D
@ -303,8 +305,8 @@ impl<'p> Python<'p> {
where D: PyDowncastFrom
{
let obj = PyObjectPtr::from_owned_ptr_or_err(self, ptr)?;
let p = pythonrun::register(self, obj);
unsafe {
let p = pythonrun::register(self, obj);
Ok(<D as PyDowncastFrom>::unchecked_downcast_from(p))
}
}
@ -363,7 +365,7 @@ impl<'p> Python<'p> {
pub fn track_object(self, obj: PyObjectPtr) -> &'p PyObject
{
pythonrun::register(self, obj)
unsafe { pythonrun::register(self, obj) }
}
}
@ -379,22 +381,23 @@ mod test {
let py = gil.python();
// Make sure builtin names are accessible
let v: i32 = py.eval("min(1, 2)", None, None).unwrap().extract().unwrap();
let v: i32 = py.eval("min(1, 2)", None, None)
.map_err(|e| e.print(py)).unwrap().extract().unwrap();
assert_eq!(v, 1);
let d = PyDict::new(py);
d.set_item("foo", 13).unwrap();
// Inject our own global namespace
let v: i32 = py.eval("foo + 29", Some(&d), None).unwrap().extract().unwrap();
let v: i32 = py.eval("foo + 29", Some(d), None).unwrap().extract().unwrap();
assert_eq!(v, 42);
// Inject our own local namespace
let v: i32 = py.eval("foo + 29", None, Some(&d)).unwrap().extract().unwrap();
let v: i32 = py.eval("foo + 29", None, Some(d)).unwrap().extract().unwrap();
assert_eq!(v, 42);
// Make sure builtin names are still accessible when using a local namespace
let v: i32 = py.eval("min(foo, 2)", None, Some(&d)).unwrap().extract().unwrap();
let v: i32 = py.eval("min(foo, 2)", None, Some(d)).unwrap().extract().unwrap();
assert_eq!(v, 2);
}

View File

@ -89,14 +89,7 @@ pub struct GILGuard {
impl Drop for GILGuard {
fn drop(&mut self) {
unsafe {
let pos = self.pos;
let pool: &'static mut Vec<PyObjectPtr> = mem::transmute(POOL);
let len = pool.len();
for ob in &mut pool[pos..len] {
ffi::Py_DECREF(ob.as_ptr());
}
pool.set_len(pos);
drain(self.pos);
ffi::PyGILState_Release(self.gstate);
}
@ -105,11 +98,46 @@ impl Drop for GILGuard {
static mut POOL: *mut Vec<PyObjectPtr> = 0 as *mut _;
pub fn register<'p>(_py: Python<'p>, obj: PyObjectPtr) -> &'p PyObject {
unsafe {
let pool: &'static mut Vec<PyObjectPtr> = mem::transmute(POOL);
pool.push(obj);
mem::transmute(&pool[pool.len()-1])
pub struct Pool {
pos: usize,
no_send: marker::PhantomData<rc::Rc<()>>,
}
impl Pool {
pub unsafe fn new() -> Pool {
let pool: &'static mut Vec<PyObject> = mem::transmute(POOL);
Pool{ pos: pool.len(), no_send: marker::PhantomData }
}
/// Retrieves the marker type that proves that the GIL was acquired.
#[inline]
pub fn python<'p>(&'p self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}
}
impl Drop for Pool {
fn drop(&mut self) {
unsafe {
drain(self.pos);
}
}
}
pub unsafe fn register<'p>(_py: Python<'p>, obj: PyObjectPtr) -> &'p PyObject {
let pool: &'static mut Vec<PyObjectPtr> = mem::transmute(POOL);
pool.push(obj);
mem::transmute(&pool[pool.len()-1])
}
pub unsafe fn drain(pos: usize) {
let pool: &'static mut Vec<PyObjectPtr> = mem::transmute(POOL);
let len = pool.len();
if pos < len {
for ob in &mut pool[pos..len] {
ffi::Py_DECREF(ob.as_ptr());
}
pool.set_len(pos);
}
}

View File

@ -5,7 +5,7 @@ use std::mem;
use std::ffi::{CStr, CString};
use std::collections::HashMap;
use {ffi, class};
use {ffi, class, pythonrun};
use err::{PyErr, PyResult};
use python::Python;
use objects::PyType;
@ -277,6 +277,7 @@ unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
debug!("DEALLOC: {:?} - {:?}", obj,
CStr::from_ptr((*(*obj).ob_type).tp_name).to_string_lossy());
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
let _pool = pythonrun::Pool::new();
let py = Python::assume_gil_acquired();
let r = <T as PyObjectAlloc<T>>::dealloc(py, obj);
mem::forget(guard);

View File

@ -87,6 +87,6 @@ fn test_buffer() {
let t = py.init(|t| TestClass{vec: vec![b' ', b'2', b'3'], token: t}).unwrap();
let d = PyDict::new(py);
d.set_item("ob", t);
d.set_item("ob", t).unwrap();
py.run("assert memoryview(ob).tobytes() == ' 23'", None, Some(d)).unwrap();
}

View File

@ -247,7 +247,7 @@ fn instance_method() {
let d = PyDict::new(py);
d.set_item("obj", obj).unwrap();
py.run("assert obj.method() == 42", None, Some(d)).unwrap();
py.run("assert obj.method.__doc__ == 'Test method'", None, Some(&d)).unwrap();
py.run("assert obj.method.__doc__ == 'Test method'", None, Some(d)).unwrap();
}
#[py::class]
@ -263,7 +263,7 @@ impl InstanceMethodWithArgs {
}
}
#[test]
//#[test]
fn instance_method_with_args() {
let gil = Python::acquire_gil();
let py = gil.python();