add weakref support #56
This commit is contained in:
parent
ce15dda5b6
commit
3ab5e4526c
|
@ -4,6 +4,8 @@ Changes
|
|||
0.1.x (xx-xx-2017)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Added weakref support #56
|
||||
|
||||
* Allow to add gc support without implementing PyGCProtocol #57
|
||||
|
||||
|
||||
|
|
|
@ -44,6 +44,23 @@ are generated only if struct contains `PyToken` attribute.
|
|||
|
||||
TODO - continue
|
||||
|
||||
## py::class macro
|
||||
|
||||
Python class generation is powered by [Procedural Macros](https://doc.rust-lang.org/book/first-edition/procedural-macros.html).
|
||||
To define python custom class, rust struct needs to be annotated with `#[py::class]` attribute.
|
||||
`py::class` macro accepts following parameters:
|
||||
|
||||
* `name=XXX` - customize class name visible to python code. By default struct name is used as
|
||||
a class name.
|
||||
* `freelist=XXX` - `freelist` parameter add support of free allocation list to custom class.
|
||||
The performance improvement applies to types that are often created and deleted in a row,
|
||||
so that they can benefit from a freelist. `XXX` is a number of items for free list.
|
||||
* `gc` - adds support for python garbage collector. classes that build with `gc` parameter
|
||||
participate in python garbage collector. If custom class contains references to other
|
||||
python object that can be collector `PyGCProtocol` trait has to be implemented.
|
||||
* `weakref` - adds support for python weak references
|
||||
|
||||
|
||||
## Constructor
|
||||
|
||||
By default it is not possible to create instance of custom class from python code.
|
||||
|
|
|
@ -158,6 +158,19 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
}
|
||||
};
|
||||
|
||||
// insert space for weak ref
|
||||
let mut has_weakref = false;
|
||||
for f in flags.iter() {
|
||||
if *f == syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_WEAKREF") {
|
||||
has_weakref = true;
|
||||
}
|
||||
}
|
||||
let weakref = if has_weakref {
|
||||
syn::Ident::from("std::mem::size_of::<*const _pyo3::ffi::PyObject>()")
|
||||
} else {
|
||||
syn::Ident::from("0")
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl _pyo3::typeob::PyTypeInfo for #cls {
|
||||
type Type = #cls;
|
||||
|
@ -167,7 +180,8 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
const SIZE: usize = Self::OFFSET as usize + std::mem::size_of::<#cls>();
|
||||
const OFFSET: isize = {
|
||||
// round base_size up to next multiple of align
|
||||
((<#base as _pyo3::typeob::PyTypeInfo>::SIZE + std::mem::align_of::<#cls>() - 1) /
|
||||
((<#base as _pyo3::typeob::PyTypeInfo>::SIZE + #weakref +
|
||||
std::mem::align_of::<#cls>() - 1) /
|
||||
std::mem::align_of::<#cls>() * std::mem::align_of::<#cls>()) as isize
|
||||
};
|
||||
|
||||
|
|
|
@ -170,6 +170,12 @@ pub fn initialize_type<'p, T>(py: Python<'p>,
|
|||
// type size
|
||||
type_object.tp_basicsize = <T as PyTypeInfo>::SIZE as ffi::Py_ssize_t;
|
||||
|
||||
// weakref support (check py3cls::py_class::impl_class)
|
||||
if T::FLAGS & PY_TYPE_FLAG_WEAKREF != 0 {
|
||||
type_object.tp_weaklistoffset = T::OFFSET -
|
||||
(std::mem::size_of::<*const ffi::PyObject>() as isize);
|
||||
}
|
||||
|
||||
// GC support
|
||||
<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
||||
|
||||
|
|
|
@ -488,6 +488,18 @@ fn gc_integration2() {
|
|||
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
|
||||
}
|
||||
|
||||
#[py::class(weakref)]
|
||||
struct WeakRefSupport {
|
||||
token: PyToken,
|
||||
}
|
||||
#[test]
|
||||
fn weakref_support() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let inst = Py::new_ref(py, |t| WeakRefSupport{token: t}).unwrap();
|
||||
py_run!(py, inst, "import weakref; assert weakref.ref(inst)() is inst");
|
||||
}
|
||||
|
||||
#[py::class]
|
||||
pub struct Len {
|
||||
l: usize,
|
||||
|
|
Loading…
Reference in New Issue