py_class!: Add support for "def __new__(cls)".
This commit is contained in:
parent
547879ef0f
commit
309182cfe8
|
@ -413,6 +413,114 @@ impl Clone for PyTypeObject {
|
|||
#[inline] fn clone(&self) -> PyTypeObject { *self }
|
||||
}
|
||||
|
||||
#[cfg(py_sys_config="Py_TRACE_REFS")]
|
||||
pub const PyTypeObject_INIT : PyTypeObject = PyTypeObject {
|
||||
_ob_next: 0 as *mut PyObject,
|
||||
_ob_prev: 0 as *mut PyObject,
|
||||
ob_refcnt: 1,
|
||||
ob_type: 0 as *mut PyTypeObject,
|
||||
ob_size: 0,
|
||||
tp_name: 0 as *const c_char,
|
||||
tp_basicsize: 0,
|
||||
tp_itemsize: 0,
|
||||
tp_dealloc: None,
|
||||
tp_print: None,
|
||||
tp_getattr: None,
|
||||
tp_setattr: None,
|
||||
tp_compare: None,
|
||||
tp_repr: None,
|
||||
tp_as_number: 0 as *mut PyNumberMethods,
|
||||
tp_as_sequence: 0 as *mut PySequenceMethods,
|
||||
tp_as_mapping: 0 as *mut PyMappingMethods,
|
||||
tp_hash: None,
|
||||
tp_call: None,
|
||||
tp_str: None,
|
||||
tp_getattro: None,
|
||||
tp_setattro: None,
|
||||
tp_as_buffer: 0 as *mut PyBufferProcs,
|
||||
tp_flags: Py_TPFLAGS_DEFAULT,
|
||||
tp_doc: 0 as *const c_char,
|
||||
tp_traverse: None,
|
||||
tp_clear: None,
|
||||
tp_richcompare: None,
|
||||
tp_weaklistoffset: 0,
|
||||
tp_iter: None,
|
||||
tp_iternext: None,
|
||||
tp_methods: 0 as *mut PyMethodDef,
|
||||
tp_members: 0 as *mut ::structmember::PyMemberDef,
|
||||
tp_getset: 0 as *mut ::descrobject::PyGetSetDef,
|
||||
tp_base: 0 as *mut PyTypeObject,
|
||||
tp_dict: 0 as *mut PyObject,
|
||||
tp_descr_get: None,
|
||||
tp_descr_set: None,
|
||||
tp_dictoffset: 0,
|
||||
tp_init: None,
|
||||
tp_alloc: None,
|
||||
tp_new: None,
|
||||
tp_free: None,
|
||||
tp_is_gc: None,
|
||||
tp_bases: 0 as *mut PyObject,
|
||||
tp_mro: 0 as *mut PyObject,
|
||||
tp_cache: 0 as *mut PyObject,
|
||||
tp_subclasses: 0 as *mut PyObject,
|
||||
tp_weaklist: 0 as *mut PyObject,
|
||||
tp_del: None,
|
||||
tp_version_tag: 0,
|
||||
};
|
||||
|
||||
#[cfg(not(py_sys_config="Py_TRACE_REFS"))]
|
||||
pub const PyTypeObject_INIT : PyTypeObject = PyTypeObject {
|
||||
ob_refcnt: 1,
|
||||
ob_type: 0 as *mut PyTypeObject,
|
||||
ob_size: 0,
|
||||
tp_name: 0 as *const c_char,
|
||||
tp_basicsize: 0,
|
||||
tp_itemsize: 0,
|
||||
tp_dealloc: None,
|
||||
tp_print: None,
|
||||
tp_getattr: None,
|
||||
tp_setattr: None,
|
||||
tp_compare: None,
|
||||
tp_repr: None,
|
||||
tp_as_number: 0 as *mut PyNumberMethods,
|
||||
tp_as_sequence: 0 as *mut PySequenceMethods,
|
||||
tp_as_mapping: 0 as *mut PyMappingMethods,
|
||||
tp_hash: None,
|
||||
tp_call: None,
|
||||
tp_str: None,
|
||||
tp_getattro: None,
|
||||
tp_setattro: None,
|
||||
tp_as_buffer: 0 as *mut PyBufferProcs,
|
||||
tp_flags: Py_TPFLAGS_DEFAULT,
|
||||
tp_doc: 0 as *const c_char,
|
||||
tp_traverse: None,
|
||||
tp_clear: None,
|
||||
tp_richcompare: None,
|
||||
tp_weaklistoffset: 0,
|
||||
tp_iter: None,
|
||||
tp_iternext: None,
|
||||
tp_methods: 0 as *mut PyMethodDef,
|
||||
tp_members: 0 as *mut ::structmember::PyMemberDef,
|
||||
tp_getset: 0 as *mut ::descrobject::PyGetSetDef,
|
||||
tp_base: 0 as *mut PyTypeObject,
|
||||
tp_dict: 0 as *mut PyObject,
|
||||
tp_descr_get: None,
|
||||
tp_descr_set: None,
|
||||
tp_dictoffset: 0,
|
||||
tp_init: None,
|
||||
tp_alloc: None,
|
||||
tp_new: None,
|
||||
tp_free: None,
|
||||
tp_is_gc: None,
|
||||
tp_bases: 0 as *mut PyObject,
|
||||
tp_mro: 0 as *mut PyObject,
|
||||
tp_cache: 0 as *mut PyObject,
|
||||
tp_subclasses: 0 as *mut PyObject,
|
||||
tp_weaklist: 0 as *mut PyObject,
|
||||
tp_del: None,
|
||||
tp_version_tag: 0,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
pub struct PyHeapTypeObject {
|
||||
|
|
|
@ -117,7 +117,7 @@ macro_rules! py_fn_impl {
|
|||
stringify!($f),
|
||||
|py| {
|
||||
py_argparse_raw!(py, Some(stringify!($f)), args, kwargs,
|
||||
[ $( { $pname : $ptype= $detail } )* ]
|
||||
[ $( { $pname : $ptype = $detail } )* ]
|
||||
{
|
||||
$f(py $(, $pname )* )
|
||||
})
|
||||
|
|
|
@ -175,7 +175,7 @@ pub mod _detail {
|
|||
///
|
||||
/// py_module_initializer!(example, initexample, PyInit_example, |py, m| {
|
||||
/// try!(m.add(py, "__doc__", "Module documentation string"));
|
||||
/// try!(m.add(py, "run", py_fn!(run())));
|
||||
/// try!(m.add(py, "run", py_fn!(py, run())));
|
||||
/// Ok(())
|
||||
/// });
|
||||
///
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
mod py_class;
|
||||
mod slots;
|
||||
#[doc(hidden)] pub mod slots;
|
||||
|
||||
use std::mem;
|
||||
use python::{self, Python};
|
||||
use libc;
|
||||
use std::{mem, ptr};
|
||||
use python::{self, Python, PythonObject};
|
||||
use objects::{PyObject, PyType};
|
||||
use err::PyResult;
|
||||
use err::{self, PyResult};
|
||||
use ffi;
|
||||
|
||||
/// Trait implemented by the types produced by the `py_class!()` macro.
|
||||
|
@ -47,13 +48,80 @@ pub fn data_new_size<T>(base_size: usize) -> usize {
|
|||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn data_get<'a, T>(_py: Python<'a>, obj: &'a PyObject, offset: usize) -> &'a T {
|
||||
let ptr = (obj.as_ptr() as *mut u8).offset(offset as isize) as *const T;
|
||||
let ptr = (obj.as_ptr() as *const u8).offset(offset as isize) as *const T;
|
||||
&*ptr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn data_init<'a, T>(_py: Python<'a>, obj: &'a PyObject, offset: usize, value: T)
|
||||
where T: Send + 'static
|
||||
{
|
||||
let ptr = (obj.as_ptr() as *mut u8).offset(offset as isize) as *mut T;
|
||||
ptr::write(ptr, value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn data_drop<'a, T>(_py: Python<'a>, obj: *mut ffi::PyObject, offset: usize) {
|
||||
let ptr = (obj as *mut u8).offset(offset as isize) as *mut T;
|
||||
ptr::drop_in_place(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub fn is_ready(_py: Python, ty: &ffi::PyTypeObject) -> bool {
|
||||
(ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0
|
||||
}
|
||||
|
||||
/// A PythonObject that is usable as a base type with the `py_class!()` macro.
|
||||
pub trait BaseObject : PythonObject {
|
||||
/// Gets the size of the object, in bytes.
|
||||
fn size() -> usize;
|
||||
|
||||
type InitType;
|
||||
|
||||
/// Allocates a new object (usually by calling ty->tp_alloc),
|
||||
/// and initializes it using init_val.
|
||||
/// `ty` must be derived from the Self type, and the resulting object
|
||||
/// must be of type `ty`.
|
||||
unsafe fn alloc(py: Python, ty: &PyType, init_val: Self::InitType) -> PyResult<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);
|
||||
}
|
||||
|
||||
impl BaseObject for PyObject {
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
mem::size_of::<ffi::PyObject>()
|
||||
}
|
||||
|
||||
type InitType = ();
|
||||
|
||||
unsafe fn alloc(py: Python, ty: &PyType, _init_val: ()) -> PyResult<PyObject> {
|
||||
let ptr = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0);
|
||||
//println!("BaseObject::alloc({:?}) = {:?}", ty.as_type_ptr(), ptr);
|
||||
err::result_from_owned_ptr(py, ptr)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
//println!("BaseObject::dealloc({:?})", ptr);
|
||||
// Unfortunately, there is no PyType_GenericFree, so
|
||||
// we have to manually un-do the work of PyType_GenericAlloc:
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
if ffi::PyType_IS_GC(ty) != 0 {
|
||||
ffi::PyObject_GC_Del(obj as *mut libc::c_void);
|
||||
} else {
|
||||
ffi::PyObject_Free(obj as *mut libc::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,15 +20,14 @@
|
|||
# Example
|
||||
```
|
||||
#[macro_use] extern crate cpython;
|
||||
use cpython::{Python, PyResult, PyType, PyDict};
|
||||
use cpython::{Python, PyResult, PyDict};
|
||||
|
||||
py_class!(class MyType |py| {
|
||||
data number: i32;
|
||||
/*
|
||||
def __new__(_cls: &PyType, arg: i32) -> PyResult<MyType> {
|
||||
Ok(MyType::create_instance(py, arg))
|
||||
def __new__(_cls, arg: i32) -> PyResult<MyType> {
|
||||
MyType::create_instance(py, arg)
|
||||
}
|
||||
def half(&self) -> PyResult<i32> {
|
||||
/*def half(&self) -> PyResult<i32> {
|
||||
println!("half() was called with self={:?}", self.number(py));
|
||||
Ok(self.number(py) / 2)
|
||||
}*/
|
||||
|
@ -44,11 +43,12 @@ fn main() {
|
|||
``` */
|
||||
#[macro_export]
|
||||
macro_rules! py_class {
|
||||
(class $name:ident |$py: ident| { $( $body:tt )* }) => (
|
||||
(class $class:ident |$py: ident| { $( $body:tt )* }) => (
|
||||
py_class_impl! {
|
||||
$name $py
|
||||
$class $py
|
||||
/* info: */ {
|
||||
/* size: */ ::std::mem::size_of::<$crate::PyObject>(),
|
||||
/* base_type: */ $crate::PyObject,
|
||||
/* size: */ <$crate::PyObject as $crate::py_class::BaseObject>::size(),
|
||||
/* data: */ [ /* { offset, name, type } */ ]
|
||||
// TODO: base type, documentation, ...
|
||||
}
|
||||
|
@ -70,51 +70,83 @@ macro_rules! py_class_impl {
|
|||
// TT muncher macro. Results are accumulated in $info $slots $impls and $members.
|
||||
|
||||
// Base case: we're done munching and can start producing code:
|
||||
{ $name:ident $py:ident
|
||||
{ $class:ident $py:ident
|
||||
/* info: */ {
|
||||
$size: expr,
|
||||
$base_type:ty,
|
||||
$size:expr,
|
||||
/* data: */ [ $( { $data_offset:expr, $data_name:ident, $data_ty:ty } )* ]
|
||||
}
|
||||
$slots:tt { $( $impl_tt:tt )* } $members:tt;
|
||||
$slots:tt { $( $imp:item )* } $members:tt;
|
||||
} => {
|
||||
struct $name($crate::PyObject);
|
||||
pyobject_newtype!($name, downcast using typeobject);
|
||||
py_coerce_item! {
|
||||
impl $name {
|
||||
$($impl_tt)*
|
||||
struct $class($crate::PyObject);
|
||||
pyobject_newtype!($class, downcast using typeobject);
|
||||
|
||||
fn create_instance(py: $crate::Python $( , $data_name : $data_ty )* ) -> $name {
|
||||
unimplemented!();
|
||||
py_coerce_item! {
|
||||
impl $crate::py_class::BaseObject for $class {
|
||||
type InitType = ( $( $data_ty, )* );
|
||||
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
$size
|
||||
}
|
||||
|
||||
unsafe fn alloc(
|
||||
py: $crate::Python,
|
||||
ty: &$crate::PyType,
|
||||
( $( $data_name, )* ): Self::InitType
|
||||
) -> $crate::PyResult<$crate::PyObject>
|
||||
{
|
||||
let obj = try!(<$base_type as $crate::py_class::BaseObject>::alloc(py, ty, ()));
|
||||
$( $crate::py_class::data_init::<$data_ty>(py, &obj, $data_offset, $data_name); )*
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(py: $crate::Python, obj: *mut $crate::_detail::ffi::PyObject) {
|
||||
$( $crate::py_class::data_drop::<$data_ty>(py, obj, $data_offset); )*
|
||||
<$base_type as $crate::py_class::BaseObject>::dealloc(py, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
$($imp)*
|
||||
py_coerce_item! {
|
||||
impl $class {
|
||||
fn create_instance(py: $crate::Python $( , $data_name : $data_ty )* ) -> $crate::PyResult<$class> {
|
||||
let obj = try!(unsafe {
|
||||
<$class as $crate::py_class::BaseObject>::alloc(
|
||||
py, &py.get_type::<$class>(), ( $($data_name,)* )
|
||||
)
|
||||
});
|
||||
return Ok($class(obj));
|
||||
|
||||
// hide statics in create_instance to avoid name conflicts
|
||||
static mut type_object : $crate::_detail::ffi::PyTypeObject
|
||||
= py_class_type_object_static_init!($name, $size, $slots);
|
||||
= py_class_type_object_static_init!($class, $slots);
|
||||
static mut init_active: bool = false;
|
||||
|
||||
// trait implementations that need direct access to type_object
|
||||
impl $crate::PythonObjectWithTypeObject for $name {
|
||||
impl $crate::PythonObjectWithTypeObject for $class {
|
||||
fn type_object(py: $crate::Python) -> $crate::PyType {
|
||||
unsafe {
|
||||
if $crate::py_class::is_ready(py, &type_object) {
|
||||
$crate::PyType::from_type_ptr(py, &mut type_object)
|
||||
} else {
|
||||
// automatically initialize the class on-demand
|
||||
<$name as $crate::py_class::PythonObjectFromPyClassMacro>::initialize(py)
|
||||
.expect("An error occurred while initializing class ")
|
||||
<$class as $crate::py_class::PythonObjectFromPyClassMacro>::initialize(py)
|
||||
.expect(concat!("An error occurred while initializing class ", stringify!($class)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::py_class::PythonObjectFromPyClassMacro for $name {
|
||||
fn initialize(py: Python) -> $crate::PyResult<$crate::PyType> {
|
||||
impl $crate::py_class::PythonObjectFromPyClassMacro for $class {
|
||||
fn initialize(py: $crate::Python) -> $crate::PyResult<$crate::PyType> {
|
||||
unsafe {
|
||||
if $crate::py_class::is_ready(py, &type_object) {
|
||||
return Ok($crate::PyType::from_type_ptr(py, &mut type_object));
|
||||
}
|
||||
assert!(!init_active,
|
||||
concat!("Reentrancy detected: already initializing class ",
|
||||
stringify!($name)));
|
||||
stringify!($class)));
|
||||
init_active = true;
|
||||
let res = init(py);
|
||||
init_active = false;
|
||||
|
@ -123,8 +155,8 @@ macro_rules! py_class_impl {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn init(py: Python) -> $crate::PyResult<$crate::PyType> {
|
||||
py_class_type_object_dynamic_init!(py, type_object, $name, $size);
|
||||
unsafe fn init(py: $crate::Python) -> $crate::PyResult<$crate::PyType> {
|
||||
py_class_type_object_dynamic_init!(py, type_object, $class);
|
||||
if $crate::_detail::ffi::PyType_Ready(&mut type_object) == 0 {
|
||||
Ok($crate::PyType::from_type_ptr(py, &mut type_object))
|
||||
} else {
|
||||
|
@ -137,16 +169,18 @@ macro_rules! py_class_impl {
|
|||
};
|
||||
|
||||
// Data declaration
|
||||
{ $name:ident $py:ident
|
||||
{ $class:ident $py:ident
|
||||
/* info: */ {
|
||||
$base_type: ty,
|
||||
$size: expr,
|
||||
[ $( $data:tt )* ]
|
||||
}
|
||||
$slots:tt { $( $impl_tt:tt )* } $members:tt;
|
||||
$slots:tt { $( $imp:item )* } $members:tt;
|
||||
data $data_name:ident : $data_type:ty; $($tail:tt)*
|
||||
} => { py_class_impl! {
|
||||
$name $py
|
||||
$class $py
|
||||
/* info: */ {
|
||||
$base_type,
|
||||
/* size: */ $crate::py_class::data_new_size::<$data_type>($size),
|
||||
/* data: */ [
|
||||
$($data)*
|
||||
|
@ -159,8 +193,9 @@ macro_rules! py_class_impl {
|
|||
}
|
||||
$slots
|
||||
/* impl: */ {
|
||||
$($impl_tt)*
|
||||
pub fn $data_name<'a>(&'a self, py: $crate::Python<'a>) -> &'a $data_type {
|
||||
$($imp)*
|
||||
impl $class {
|
||||
fn $data_name<'a>(&'a self, py: $crate::Python<'a>) -> &'a $data_type {
|
||||
unsafe {
|
||||
$crate::py_class::data_get::<$data_type>(
|
||||
py,
|
||||
|
@ -170,8 +205,79 @@ macro_rules! py_class_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$members;
|
||||
$($tail)*
|
||||
}}
|
||||
}};
|
||||
|
||||
// def __new__(cls)
|
||||
{ $class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
||||
$as_number:tt $as_sequence:tt
|
||||
}
|
||||
{ $( $imp:item )* } $members:tt;
|
||||
def __new__ ($cls:ident)
|
||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||
} => { py_class_impl! {
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
/* type_slots */ [
|
||||
$( $slot_name : $slot_value, )*
|
||||
tp_new: Some(py_class_wrap_newfunc!($class::__new__ [])),
|
||||
]
|
||||
$as_number $as_sequence
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_class_impl_item! { $class, $py, __new__($cls: &$crate::PyType) $res_type; { $($body)* } [] }
|
||||
}
|
||||
$members;
|
||||
$($tail)*
|
||||
}};
|
||||
// def __new__(cls, params)
|
||||
{ $class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
||||
$as_number:tt $as_sequence:tt
|
||||
}
|
||||
{ $( $imp:item )* } $members:tt;
|
||||
def __new__ ($cls:ident, $($p:tt)+)
|
||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||
} => { py_class_impl! {
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
/* type_slots */ [
|
||||
$( $slot_name : $slot_value, )*
|
||||
tp_new: Some(py_argparse_parse_plist_impl!{
|
||||
py_class_wrap_newfunc {$class::__new__}
|
||||
[] ($($p)+,)
|
||||
}),
|
||||
]
|
||||
$as_number $as_sequence
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_argparse_parse_plist_impl!{
|
||||
py_class_impl_item { $class, $py, __new__($cls: &$crate::PyType) $res_type; { $($body)* } }
|
||||
[] ($($p)+,)
|
||||
}
|
||||
}
|
||||
$members;
|
||||
$($tail)*
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_class_impl_item {
|
||||
{ $class:ident, $py:ident, $name:ident( $( $pname1:ident : $ptype1:ty ),* )
|
||||
$res_type:ty; $body:block [ $( { $pname2:ident : $ptype2:ty = $detail:tt } )* ]
|
||||
} => {
|
||||
impl $class {
|
||||
pub fn __new__($py: $crate::Python $( , $pname1: $ptype1 )* $( , $pname2: $ptype2 )* )
|
||||
-> $res_type $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,17 +16,21 @@
|
|||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use ffi;
|
||||
use python::Python;
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_class_type_object_static_init {
|
||||
($name:ident, $size:expr,
|
||||
($class_name:ident,
|
||||
/* slots: */ {
|
||||
/* type_slots */ [ $( $slotname:ident : $slotvalue:expr, )* ]
|
||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
||||
$as_number:tt
|
||||
$as_sequence:tt
|
||||
}) => (
|
||||
$crate::_detail::ffi::PyTypeObject {
|
||||
$( $slotname : $slotvalue, )*
|
||||
$( $slot_name : $slot_value, )*
|
||||
tp_dealloc: Some($crate::py_class::slots::tp_dealloc_callback::<$class_name>),
|
||||
..
|
||||
$crate::_detail::ffi::PyTypeObject_INIT
|
||||
}
|
||||
|
@ -37,13 +41,46 @@ macro_rules! py_class_type_object_static_init {
|
|||
#[doc(hidden)]
|
||||
macro_rules! py_class_type_object_dynamic_init {
|
||||
// initialize those fields of PyTypeObject that we couldn't initialize statically
|
||||
($py:ident, $type_object:ident, $name: ident, $size: expr) => {{
|
||||
$type_object.tp_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
|
||||
$type_object.tp_basicsize = $size as $crate::_detail::ffi::Py_ssize_t;
|
||||
($py:ident, $type_object:ident, $class_name: ident) => {{
|
||||
$type_object.tp_name = concat!(stringify!($class_name), "\0").as_ptr() as *const _;
|
||||
$type_object.tp_basicsize = <$class_name as $crate::py_class::BaseObject>::size()
|
||||
as $crate::_detail::ffi::Py_ssize_t;
|
||||
}}
|
||||
}
|
||||
|
||||
use ffi;
|
||||
|
||||
|
||||
pub unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
|
||||
where T: super::BaseObject
|
||||
{
|
||||
abort_on_panic!({
|
||||
let py = Python::assume_gil_acquired();
|
||||
T::dealloc(py, obj)
|
||||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_class_wrap_newfunc {
|
||||
($class:ident :: $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
|
||||
unsafe extern "C" fn wrap_newfunc<DUMMY>(
|
||||
cls: *mut $crate::_detail::ffi::PyTypeObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!(), "()");
|
||||
$crate::_detail::handle_callback(
|
||||
LOCATION,
|
||||
|py| {
|
||||
py_argparse_raw!(py, Some(LOCATION), args, kwargs,
|
||||
[ $( { $pname : $ptype = $detail } )* ]
|
||||
{
|
||||
let cls = $crate::PyType::from_type_ptr(py, cls);
|
||||
let ret = $class::$f(py, &cls $(, $pname )* );
|
||||
$crate::PyDrop::release_ref(cls, py);
|
||||
ret
|
||||
})
|
||||
})
|
||||
}
|
||||
wrap_newfunc::<()>
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ use pythonrun::GILGuard;
|
|||
pub struct Python<'p>(PhantomData<&'p GILGuard>);
|
||||
|
||||
/// Trait implemented by all Python object types.
|
||||
pub trait PythonObject : ::conversion::ToPyObject + Sized + 'static {
|
||||
pub trait PythonObject : ::conversion::ToPyObject + Send + Sized + 'static {
|
||||
/// Casts the Python object to PyObject.
|
||||
fn as_object(&self) -> &PyObject;
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#[macro_use] extern crate cpython;
|
||||
|
||||
use cpython::{PyResult, Python, NoArgs, ObjectProtocol, PyDict};
|
||||
use cpython::{PyResult, Python, NoArgs, ObjectProtocol};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn empty_class() {
|
||||
py_class!(class Empty |py| { });
|
||||
|
||||
|
@ -18,9 +19,9 @@ fn empty_class() {
|
|||
#[test]
|
||||
fn empty_class_with_new() {
|
||||
py_class!(class Empty |py| {
|
||||
/*def __new__(cls) -> PyResult<Empty> {
|
||||
Ok(Empty::create_instance(py))
|
||||
}*/
|
||||
def __new__(_cls) -> PyResult<Empty> {
|
||||
Empty::create_instance(py)
|
||||
}
|
||||
});
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -30,6 +31,7 @@ fn empty_class_with_new() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn data_is_dropped() {
|
||||
struct MyObj {
|
||||
drop_called: Arc<AtomicBool>
|
||||
|
|
Loading…
Reference in a new issue