Commit 94a7a545 authored by Georges Racinet's avatar Georges Racinet
Browse files

Sharing multiple reference by forcing the lifetime

This should be the general principle, but this first implementation
does not provide any safeguards. In particular, I expect that
clearing or heavily resizing the underlying HashSet while an iterator
has a reference on it should end up in segfaults.
parent ae55368335ce
......@@ -11,6 +11,7 @@ extern crate cpython;
use cpython::*;
use std::cell::RefCell;
use std::collections::hash_set::Iter;
use std::collections::HashSet;
type Inner = HashSet<u32>;
......@@ -39,8 +40,34 @@ py_class!(class RustSet |py| {
Ok(py.None())
}
def __iter__(&self) -> PyResult<RustSetIterator> {
let ptr = self.hs(py).as_ptr();
let as_static: &'static Inner = unsafe {&*ptr};
RustSetIterator::create_instance(
py,
self.clone_ref(py),
RefCell::new(as_static.iter()))
}
});
py_class!(class RustSetIterator |py| {
data hs: RustSet;
data it: RefCell<Iter<'static, u32>>;
def __next__(&self) -> PyResult<Option<u32>> {
Ok(self.it(py).borrow_mut().next().map(|r| *r))
}
def __iter__(&self) -> PyResult<Self> {
Ok(self.clone_ref(py))
}
});
py_module_initializer!(shared_ref, initshared_ref, PyInit_shared_ref, |py, m| {
m.add(
py,
......
import sys
try:
from .shared_ref import RustSet
except ImportError:
import sys
sys.stderr.write("Rust extension not found. Please run 'cargo build' "
"first (without '--release')\n")
sys.exit(1)
......@@ -19,5 +20,24 @@ def test_basic():
assert 65 not in rs
def test_iter():
rs = RustSet()
start_count = sys.getrefcount(rs) # should be 2 (see Python doc)
rs.extend(range(4))
it = iter(rs)
assert sys.getrefcount(rs) == start_count + 1
assert set(it) == {0, 1, 2, 3}
del it
assert sys.getrefcount(rs) == start_count
it2 = iter(rs)
del rs
assert set(it2) == {0, 1, 2, 3}
del it2
def run():
test_basic()
test_iter()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment