Skip to content

Commit

Permalink
add weakref support #56
Browse files Browse the repository at this point in the history
  • Loading branch information
fafhrd91 committed Jul 24, 2017
1 parent ce15dda commit 3ab5e45
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Changes
0.1.x (xx-xx-2017)
^^^^^^^^^^^^^^^^^^

* Added weakref support #56

* Allow to add gc support without implementing PyGCProtocol #57


Expand Down
17 changes: 17 additions & 0 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
16 changes: 15 additions & 1 deletion pyo3cls/src/py_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
};

Expand Down
6 changes: 6 additions & 0 deletions src/typeob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 12 additions & 0 deletions tests/test_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 3ab5e45

Please sign in to comment.