refactor object allocation system
This commit is contained in:
parent
bf793b4b71
commit
03b6e5c122
|
@ -269,9 +269,10 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
let py = gil.python();
|
||||
|
||||
// automatically initialize the class on-demand
|
||||
_pyo3::typeob::initialize_type::<#cls>(py, None).expect(
|
||||
format!("An error occurred while initializing class {}",
|
||||
<#cls as _pyo3::typeob::PyTypeInfo>::NAME).as_ref());
|
||||
_pyo3::typeob::initialize_type::<#cls>(py, None)
|
||||
.map_err(|e| e.print(py))
|
||||
.expect(format!("An error occurred while initializing class {}",
|
||||
<#cls as _pyo3::typeob::PyTypeInfo>::NAME).as_ref());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ impl<T> FreeList<T> {
|
|||
|
||||
impl<T> PyObjectAlloc<T> for T where T: PyObjectWithFreeList {
|
||||
|
||||
unsafe fn alloc(_py: Python, value: T) -> PyResult<*mut ffi::PyObject> {
|
||||
unsafe fn alloc(_py: Python) -> PyResult<*mut ffi::PyObject> {
|
||||
let obj = if let Some(obj) = <T as PyObjectWithFreeList>::get_free_list().pop() {
|
||||
ffi::PyObject_Init(obj, <T as PyTypeInfo>::type_object());
|
||||
obj
|
||||
|
@ -81,54 +81,59 @@ impl<T> PyObjectAlloc<T> for T where T: PyObjectWithFreeList {
|
|||
ffi::PyType_GenericAlloc(<T as PyTypeInfo>::type_object(), 0)
|
||||
};
|
||||
|
||||
let ptr = (obj as *mut u8).offset(<T as PyTypeInfo>::OFFSET) as *mut T;
|
||||
std::ptr::write(ptr, value);
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
#[cfg(Py_3)]
|
||||
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
let ptr = (obj as *mut u8).offset(<T as PyTypeInfo>::OFFSET) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
|
||||
Self::drop(py, obj);
|
||||
|
||||
if ffi::PyObject_CallFinalizerFromDealloc(obj) < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if let Some(obj) = <T as PyObjectWithFreeList>::get_free_list().insert(obj) {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
match (*T::type_object()).tp_free {
|
||||
Some(free) => free(obj as *mut ::c_void),
|
||||
None => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_3))]
|
||||
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
let ptr = (obj as *mut u8).offset(<T as PyTypeInfo>::OFFSET) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
|
||||
Self::drop(py, obj);
|
||||
|
||||
if let Some(obj) = <T as PyObjectWithFreeList>::get_free_list().insert(obj) {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
match (*T::type_object()).tp_free {
|
||||
Some(free) => free(obj as *mut ::c_void),
|
||||
None => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use objects::PyObjectRef;
|
|||
use objectprotocol::ObjectProtocol;
|
||||
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
|
||||
use python::{Python, IntoPyPointer, ToPyPointer};
|
||||
use typeob::{PyTypeInfo, PyObjectAlloc};
|
||||
use typeob::{PyTypeInfo, PyTypeObject};
|
||||
|
||||
|
||||
pub struct PyToken(PhantomData<Rc<()>>);
|
||||
|
@ -165,13 +165,13 @@ impl<T> Py<T> where T: PyTypeInfo,
|
|||
/// Returns `Py<T>`.
|
||||
pub fn new<F>(py: Python, f: F) -> PyResult<Py<T>>
|
||||
where F: FnOnce(::PyToken) -> T,
|
||||
T: PyObjectAlloc<T>
|
||||
T: PyTypeObject + PyTypeInfo
|
||||
{
|
||||
let ob = f(PyToken(PhantomData));
|
||||
let ob = <T as PyTypeObject>::create(py)?;
|
||||
ob.init(f)?;
|
||||
|
||||
let ob = unsafe {
|
||||
let ob = try!(<T as PyObjectAlloc<T>>::alloc(py, ob));
|
||||
Py::from_owned_ptr(ob)
|
||||
Py::from_owned_ptr(ob.into_ptr())
|
||||
};
|
||||
Ok(ob)
|
||||
}
|
||||
|
@ -180,13 +180,13 @@ impl<T> Py<T> where T: PyTypeInfo,
|
|||
/// Returns references to `T`
|
||||
pub fn new_ref<F>(py: Python, f: F) -> PyResult<&T>
|
||||
where F: FnOnce(::PyToken) -> T,
|
||||
T: PyObjectAlloc<T>
|
||||
T: PyTypeObject + PyTypeInfo
|
||||
{
|
||||
let ob = f(PyToken(PhantomData));
|
||||
let ob = <T as PyTypeObject>::create(py)?;
|
||||
ob.init(f)?;
|
||||
|
||||
unsafe {
|
||||
let ob = try!(<T as PyObjectAlloc<T>>::alloc(py, ob));
|
||||
Ok(py.from_owned_ptr(ob))
|
||||
Ok(py.from_owned_ptr(ob.into_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,13 +194,13 @@ impl<T> Py<T> where T: PyTypeInfo,
|
|||
/// Returns mutable references to `T`
|
||||
pub fn new_mut<F>(py: Python, f: F) -> PyResult<&mut T>
|
||||
where F: FnOnce(::PyToken) -> T,
|
||||
T: PyObjectAlloc<T>
|
||||
T: PyTypeObject + PyTypeInfo
|
||||
{
|
||||
let ob = f(PyToken(PhantomData));
|
||||
let ob = <T as PyTypeObject>::create(py)?;
|
||||
ob.init(f)?;
|
||||
|
||||
unsafe {
|
||||
let ob = try!(<T as PyObjectAlloc<T>>::alloc(py, ob));
|
||||
Ok(py.mut_from_owned_ptr(ob))
|
||||
Ok(py.mut_from_owned_ptr(ob.into_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use ffi;
|
|||
use pythonrun;
|
||||
use err::{PyErr, PyResult, PyDowncastError};
|
||||
use instance::{AsPyRef, PyObjectWithToken};
|
||||
use objects::PyObjectRef;
|
||||
use objects::{PyTuple, PyObjectRef};
|
||||
use conversion::{ToPyObject, ToBorrowedObject,
|
||||
IntoPyObject, IntoPyTuple, FromPyObject, PyTryFrom};
|
||||
use python::{Python, ToPyPointer, IntoPyPointer, IntoPyDictPointer};
|
||||
|
@ -179,6 +179,33 @@ impl PyObject {
|
|||
result
|
||||
}
|
||||
|
||||
/// Calls the object without arguments.
|
||||
/// This is equivalent to the Python expression: 'self()'
|
||||
pub fn call0(&self, py: Python) -> PyResult<PyObject>
|
||||
{
|
||||
let args = PyTuple::empty(py).into_ptr();
|
||||
let result = unsafe {
|
||||
PyObject::from_owned_ptr_or_err(
|
||||
py, ffi::PyObject_Call(self.as_ptr(), args, std::ptr::null_mut()))
|
||||
};
|
||||
py.xdecref(args);
|
||||
result
|
||||
}
|
||||
|
||||
/// Calls the object.
|
||||
/// This is equivalent to the Python expression: 'self(*args)'
|
||||
pub fn call1<A>(&self, py: Python, args: A) -> PyResult<PyObject>
|
||||
where A: IntoPyTuple
|
||||
{
|
||||
let args = args.into_tuple(py).into_ptr();
|
||||
let result = unsafe {
|
||||
PyObject::from_owned_ptr_or_err(
|
||||
py, ffi::PyObject_Call(self.as_ptr(), args, std::ptr::null_mut()))
|
||||
};
|
||||
py.xdecref(args);
|
||||
result
|
||||
}
|
||||
|
||||
/// Calls a method on the object.
|
||||
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
|
||||
pub fn call_method<A, K>(&self, py: Python,
|
||||
|
@ -198,6 +225,37 @@ impl PyObject {
|
|||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Calls a method on the object.
|
||||
/// This is equivalent to the Python expression: 'self.name()'
|
||||
pub fn call_method0(&self, py: Python, name: &str) -> PyResult<PyObject>
|
||||
{
|
||||
name.with_borrowed_ptr(py, |name| unsafe {
|
||||
let args = PyTuple::empty(py).into_ptr();
|
||||
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
|
||||
let result = PyObject::from_owned_ptr_or_err(
|
||||
py, ffi::PyObject_Call(ptr, args, std::ptr::null_mut()));
|
||||
ffi::Py_DECREF(ptr);
|
||||
py.xdecref(args);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Calls a method on the object.
|
||||
/// This is equivalent to the Python expression: 'self.name(*args)'
|
||||
pub fn call_method1<A>(&self, py: Python, name: &str, args: A) -> PyResult<PyObject>
|
||||
where A: IntoPyTuple
|
||||
{
|
||||
name.with_borrowed_ptr(py, |name| unsafe {
|
||||
let args = args.into_tuple(py).into_ptr();
|
||||
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
|
||||
let result = PyObject::from_owned_ptr_or_err(
|
||||
py, ffi::PyObject_Call(ptr, args, std::ptr::null_mut()));
|
||||
ffi::Py_DECREF(ptr);
|
||||
py.xdecref(args);
|
||||
result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsPyRef<PyObjectRef> for PyObject {
|
||||
|
|
|
@ -150,6 +150,9 @@ pub trait ObjectProtocol {
|
|||
/// Gets the Python base object for this object.
|
||||
fn get_base(&self) -> &<Self as PyTypeInfo>::BaseType where Self: PyTypeInfo;
|
||||
|
||||
/// Gets the Python base object for this object.
|
||||
fn get_mut_base(&self) -> &mut <Self as PyTypeInfo>::BaseType where Self: PyTypeInfo;
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
fn cast_as<'a, D>(&'a self) -> Result<&'a D, <D as PyTryFrom>::Error>
|
||||
where D: PyTryFrom<Error=PyDowncastError>,
|
||||
|
@ -418,6 +421,11 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
|
|||
unsafe { self.py().from_borrowed_ptr(self.as_ptr()) }
|
||||
}
|
||||
|
||||
fn get_mut_base(&self) -> &mut <Self as PyTypeInfo>::BaseType where Self: PyTypeInfo
|
||||
{
|
||||
unsafe { self.py().mut_from_borrowed_ptr(self.as_ptr()) }
|
||||
}
|
||||
|
||||
fn cast_as<'a, D>(&'a self) -> Result<&'a D, <D as PyTryFrom>::Error>
|
||||
where D: PyTryFrom<Error=PyDowncastError>,
|
||||
&'a PyObjectRef: std::convert::From<&'a Self>
|
||||
|
|
|
@ -105,7 +105,7 @@ mod test {
|
|||
let err: PyErr = gaierror.into();
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item("socket", py.import("socket").unwrap()).unwrap();
|
||||
d.set_item("socket", py.import("socket").map_err(|e| e.print(py)).unwrap()).unwrap();
|
||||
d.set_item("exc", err).unwrap();
|
||||
|
||||
py.run("assert isinstance(exc, socket.gaierror)", None, Some(d)).unwrap();
|
||||
|
|
|
@ -88,6 +88,21 @@ impl PyModule {
|
|||
self.getattr(name)?.call(args, kwargs)
|
||||
}
|
||||
|
||||
/// Calls a function in the module.
|
||||
/// This is equivalent to the Python expression: `getattr(module, name)()`
|
||||
pub fn call0(&self, name: &str) -> PyResult<&PyObjectRef>
|
||||
{
|
||||
self.getattr(name)?.call0()
|
||||
}
|
||||
|
||||
/// Calls a function in the module.
|
||||
/// This is equivalent to the Python expression: `getattr(module, name)(*args)`
|
||||
pub fn call1<A>(&self, name: &str, args: A) -> PyResult<&PyObjectRef>
|
||||
where A: IntoPyTuple
|
||||
{
|
||||
self.getattr(name)?.call1(args)
|
||||
}
|
||||
|
||||
/// Gets a member from the module.
|
||||
/// This is equivalent to the Python expression: `getattr(module, name)`
|
||||
pub fn get(&self, name: &str) -> PyResult<&PyObjectRef>
|
||||
|
|
|
@ -349,6 +349,20 @@ impl<'p> Python<'p> {
|
|||
self.unchecked_downcast(p)
|
||||
}
|
||||
|
||||
/// Register borrowed `ffi::PyObject` pointer in release pool.
|
||||
/// Panics if the pointer is `null`.
|
||||
/// do unchecked downcast to specific type.
|
||||
pub unsafe fn mut_from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
|
||||
where T: PyTypeInfo
|
||||
{
|
||||
if ptr.is_null() {
|
||||
::err::panic_after_error();
|
||||
} else {
|
||||
let p = pythonrun::register_borrowed(self, ptr);
|
||||
self.unchecked_mut_downcast(p)
|
||||
}
|
||||
}
|
||||
|
||||
/// Register borrowed `ffi::PyObject` pointer in release pool.
|
||||
/// Returns `Err(PyErr)` if the pointer is `null`.
|
||||
/// do unchecked downcast to specific type.
|
||||
|
@ -377,16 +391,6 @@ impl<'p> Python<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Register borrowed `ffi::PyObject` pointer in release pool.
|
||||
/// Panics if the pointer is `null`.
|
||||
/// do unchecked downcast to specific `T`, returns mutable reference.
|
||||
pub unsafe fn mut_from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'p mut T
|
||||
where T: PyTypeInfo
|
||||
{
|
||||
let p = pythonrun::register_borrowed(self, ptr);
|
||||
self.unchecked_mut_downcast(p)
|
||||
}
|
||||
|
||||
/// Release PyObject reference.
|
||||
#[inline]
|
||||
pub fn release<T>(self, ob: T) where T: IntoPyPointer {
|
||||
|
|
117
src/typeob.rs
117
src/typeob.rs
|
@ -121,6 +121,23 @@ impl PyRawObject {
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub unsafe fn new_with_ptr(py: Python,
|
||||
ptr: *mut ffi::PyObject,
|
||||
tp_ptr: *mut ffi::PyTypeObject,
|
||||
curr_ptr: *mut ffi::PyTypeObject) -> PyResult<PyRawObject> {
|
||||
if !ptr.is_null() {
|
||||
Ok(PyRawObject {
|
||||
ptr: ptr,
|
||||
tp_ptr: tp_ptr,
|
||||
curr_ptr: curr_ptr,
|
||||
initialized: 0,
|
||||
})
|
||||
} else {
|
||||
PyErr::fetch(py).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize memory using value.
|
||||
/// `PyRawObject` is used by class `__new__` method.
|
||||
/// ```
|
||||
|
@ -184,67 +201,88 @@ impl PyObjectWithToken for PyRawObject {
|
|||
pub trait PyObjectAlloc<T> {
|
||||
|
||||
/// Allocates a new object (usually by calling ty->tp_alloc),
|
||||
/// and initializes it using value.
|
||||
unsafe fn alloc(py: Python, value: T) -> PyResult<*mut ffi::PyObject>;
|
||||
unsafe fn alloc(py: Python) -> PyResult<*mut ffi::PyObject>;
|
||||
|
||||
/// Calls the rust destructor for the object and frees the memory
|
||||
/// (usually by calling ptr->ob_type->tp_free).
|
||||
/// This function is used as tp_dealloc implementation.
|
||||
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject);
|
||||
|
||||
/// Calls the rust destructor for the object.
|
||||
unsafe fn drop(_py: Python, _obj: *mut ffi::PyObject) {}
|
||||
}
|
||||
|
||||
impl<T> PyObjectAlloc<T> for T where T : PyTypeInfo {
|
||||
|
||||
default unsafe fn alloc(_py: Python, value: T) -> PyResult<*mut ffi::PyObject> {
|
||||
#[allow(unconditional_recursion)]
|
||||
/// Calls the rust destructor for the object.
|
||||
default unsafe fn drop(py: Python, obj: *mut ffi::PyObject) {
|
||||
if T::OFFSET != 0 {
|
||||
let ptr = (obj as *mut u8).offset(T::OFFSET) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
|
||||
T::BaseType::drop(py, obj);
|
||||
}
|
||||
}
|
||||
|
||||
default unsafe fn alloc(_py: Python) -> PyResult<*mut ffi::PyObject> {
|
||||
// TODO: remove this
|
||||
T::init_type();
|
||||
|
||||
let obj = ffi::PyType_GenericAlloc(T::type_object(), 0);
|
||||
let ptr = (obj as *mut u8).offset(T::OFFSET) as *mut T;
|
||||
std::ptr::write(ptr, value);
|
||||
let tp_ptr = T::type_object();
|
||||
let alloc = (*tp_ptr).tp_alloc.unwrap_or(ffi::PyType_GenericAlloc);
|
||||
let obj = alloc(tp_ptr, 0);
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
#[cfg(Py_3)]
|
||||
default unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
let ptr = (obj as *mut u8).offset(T::OFFSET) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
default unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
|
||||
Self::drop(py, obj);
|
||||
|
||||
if ffi::PyObject_CallFinalizerFromDealloc(obj) < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
match (*T::type_object()).tp_free {
|
||||
Some(free) => free(obj as *mut ::c_void),
|
||||
None => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_3))]
|
||||
default unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
let ptr = (obj as *mut u8).offset(T::OFFSET) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
default unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
|
||||
Self::drop(py, obj);
|
||||
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
match (*T::type_object()).tp_free {
|
||||
Some(free) => free(obj as *mut ::c_void),
|
||||
None => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut ::c_void);
|
||||
}
|
||||
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
||||
// so we need to call DECREF here:
|
||||
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,6 +296,21 @@ pub trait PyTypeObject {
|
|||
/// Retrieves the type object for this Python object type.
|
||||
fn type_object() -> Py<PyType>;
|
||||
|
||||
/// Create PyRawObject which can be initialized with rust value
|
||||
#[must_use]
|
||||
fn create(py: Python) -> PyResult<PyRawObject>
|
||||
where Self: Sized + PyObjectAlloc<Self> + PyTypeInfo
|
||||
{
|
||||
<Self as PyTypeObject>::init_type();
|
||||
|
||||
unsafe {
|
||||
let ptr = <Self as PyObjectAlloc<Self>>::alloc(py)?;
|
||||
PyRawObject::new_with_ptr(
|
||||
py, ptr,
|
||||
<Self as PyTypeInfo>::type_object(),
|
||||
<Self as PyTypeInfo>::type_object())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
|
||||
|
|
|
@ -1307,7 +1307,7 @@ fn getter_setter_autogen() {
|
|||
#[py::class]
|
||||
struct BaseClass {
|
||||
#[prop(get)]
|
||||
val1: usize
|
||||
val1: usize,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
|
@ -1321,7 +1321,7 @@ impl BaseClass {
|
|||
#[py::class(base=BaseClass)]
|
||||
struct SubClass {
|
||||
#[prop(get)]
|
||||
val2: usize
|
||||
val2: usize,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
|
@ -1342,3 +1342,72 @@ fn inheritance_with_new_methods() {
|
|||
let inst = typeobj.call(NoArgs, NoArgs).unwrap();
|
||||
py_run!(py, inst, "assert inst.val1 == 10; assert inst.val2 == 5");
|
||||
}
|
||||
|
||||
|
||||
#[py::class]
|
||||
struct BaseClassWithDrop {
|
||||
token: PyToken,
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
impl BaseClassWithDrop {
|
||||
#[new]
|
||||
fn __new__(obj: &PyRawObject) -> PyResult<()> {
|
||||
obj.init(|t| BaseClassWithDrop{token: t, data: None})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BaseClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref mut data) = self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[py::class(base=BaseClassWithDrop)]
|
||||
struct SubClassWithDrop {
|
||||
token: PyToken,
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
impl SubClassWithDrop {
|
||||
#[new]
|
||||
fn __new__(obj: &PyRawObject) -> PyResult<()> {
|
||||
obj.init(|t| SubClassWithDrop{token: t, data: None})?;
|
||||
BaseClassWithDrop::__new__(obj)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SubClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref mut data) = self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inheritance_with_new_methods_with_drop() {
|
||||
let drop_called1 = Arc::new(AtomicBool::new(false));
|
||||
let drop_called2 = Arc::new(AtomicBool::new(false));
|
||||
|
||||
{
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typebase = py.get_type::<BaseClassWithDrop>();
|
||||
let typeobj = py.get_type::<SubClassWithDrop>();
|
||||
let inst = typeobj.call(NoArgs, NoArgs).unwrap();
|
||||
|
||||
let mut obj = SubClassWithDrop::try_from_mut(inst).unwrap();
|
||||
obj.data = Some(drop_called1.clone());
|
||||
|
||||
let mut base = obj.get_mut_base();
|
||||
base.data = Some(drop_called2.clone());
|
||||
}
|
||||
|
||||
assert!(drop_called1.load(Ordering::Relaxed));
|
||||
assert!(drop_called2.load(Ordering::Relaxed));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue