comparison rust/hg-cpython/src/ref_sharing.rs @ 43284:ce6dd1cee4c8

rust-cpython: put leaked reference in PyLeakedRef The next patch will make PyLeakedRef manage the lifetime of the underlying object. leak_handle.data.take() will be removed soon.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 15 Sep 2019 22:06:19 +0900
parents 00222775d59b
children ffc1fbd7d1f5
comparison
equal deleted inserted replaced
43283:96eb9ef777a8 43284:ce6dd1cee4c8
185 185
186 pub fn borrow_mut(&self) -> PyResult<PyRefMut<'a, T>> { 186 pub fn borrow_mut(&self) -> PyResult<PyRefMut<'a, T>> {
187 self.data.borrow_mut(self.py) 187 self.data.borrow_mut(self.py)
188 } 188 }
189 189
190 /// Returns a leaked reference and its management object. 190 /// Returns a leaked reference temporarily held by its management object.
191 /// 191 ///
192 /// # Safety 192 /// # Safety
193 /// 193 ///
194 /// It's up to you to make sure that the management object lives 194 /// It's up to you to make sure that the management object lives
195 /// longer than the leaked reference. Otherwise, you'll get a 195 /// longer than the leaked reference. Otherwise, you'll get a
196 /// dangling reference. 196 /// dangling reference.
197 pub unsafe fn leak_immutable( 197 pub unsafe fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> {
198 &self,
199 ) -> PyResult<(PyLeakedRef, &'static T)> {
200 let (static_ref, static_state_ref) = self 198 let (static_ref, static_state_ref) = self
201 .data 199 .data
202 .py_shared_state 200 .py_shared_state
203 .leak_immutable(self.py, self.data)?; 201 .leak_immutable(self.py, self.data)?;
204 let leak_handle = 202 Ok(PyLeakedRef::new(
205 PyLeakedRef::new(self.py, self.owner, static_state_ref); 203 self.py,
206 Ok((leak_handle, static_ref)) 204 self.owner,
205 static_ref,
206 static_state_ref,
207 ))
207 } 208 }
208 } 209 }
209 210
210 /// Holds a mutable reference to data shared between Python and Rust. 211 /// Holds a mutable reference to data shared between Python and Rust.
211 pub struct PyRefMut<'a, T> { 212 pub struct PyRefMut<'a, T> {
316 317
317 /// Manage immutable references to `PyObject` leaked into Python iterators. 318 /// Manage immutable references to `PyObject` leaked into Python iterators.
318 /// 319 ///
319 /// In truth, this does not represent leaked references themselves; 320 /// In truth, this does not represent leaked references themselves;
320 /// it is instead useful alongside them to manage them. 321 /// it is instead useful alongside them to manage them.
321 pub struct PyLeakedRef { 322 pub struct PyLeakedRef<T> {
322 _inner: PyObject, 323 _inner: PyObject,
324 pub data: Option<T>, // TODO: remove pub
323 py_shared_state: &'static PySharedState, 325 py_shared_state: &'static PySharedState,
324 } 326 }
325 327
326 impl PyLeakedRef { 328 impl<T> PyLeakedRef<T> {
327 /// # Safety 329 /// # Safety
328 /// 330 ///
329 /// The `py_shared_state` must be owned by the `inner` Python object. 331 /// The `py_shared_state` must be owned by the `inner` Python object.
330 // Marked as unsafe so client code wouldn't construct PyLeakedRef 332 // Marked as unsafe so client code wouldn't construct PyLeakedRef
331 // struct by mistake. Its drop() is unsafe. 333 // struct by mistake. Its drop() is unsafe.
332 pub unsafe fn new( 334 pub unsafe fn new(
333 py: Python, 335 py: Python,
334 inner: &PyObject, 336 inner: &PyObject,
337 data: T,
335 py_shared_state: &'static PySharedState, 338 py_shared_state: &'static PySharedState,
336 ) -> Self { 339 ) -> Self {
337 Self { 340 Self {
338 _inner: inner.clone_ref(py), 341 _inner: inner.clone_ref(py),
342 data: Some(data),
339 py_shared_state, 343 py_shared_state,
340 } 344 }
341 } 345 }
342 } 346 }
343 347
344 impl Drop for PyLeakedRef { 348 impl<T> Drop for PyLeakedRef<T> {
345 fn drop(&mut self) { 349 fn drop(&mut self) {
346 // py_shared_state should be alive since we do have 350 // py_shared_state should be alive since we do have
347 // a Python reference to the owner object. Taking GIL makes 351 // a Python reference to the owner object. Taking GIL makes
348 // sure that the state is only accessed by this thread. 352 // sure that the state is only accessed by this thread.
349 let gil = Python::acquire_gil(); 353 let gil = Python::acquire_gil();
377 /// 381 ///
378 /// py_class!(pub class MyType |py| { 382 /// py_class!(pub class MyType |py| {
379 /// data inner: PySharedRefCell<MyStruct>; 383 /// data inner: PySharedRefCell<MyStruct>;
380 /// 384 ///
381 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { 385 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
382 /// let (leak_handle, leaked_ref) = 386 /// let mut leak_handle =
383 /// unsafe { self.inner_shared(py).leak_immutable()? }; 387 /// unsafe { self.inner_shared(py).leak_immutable()? };
388 /// let leaked_ref = leak_handle.data.take().unwrap();
384 /// MyTypeItemsIterator::from_inner( 389 /// MyTypeItemsIterator::from_inner(
385 /// py, 390 /// py,
386 /// leak_handle, 391 /// leak_handle,
387 /// leaked_ref.iter(), 392 /// leaked_ref.iter(),
388 /// ) 393 /// )
404 /// 409 ///
405 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef); 410 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
406 /// 411 ///
407 /// py_shared_iterator!( 412 /// py_shared_iterator!(
408 /// MyTypeItemsIterator, 413 /// MyTypeItemsIterator,
409 /// PyLeakedRef, 414 /// PyLeakedRef<&'static MyStruct>,
410 /// HashMap<'static, Vec<u8>, Vec<u8>>, 415 /// HashMap<'static, Vec<u8>, Vec<u8>>,
411 /// MyType::translate_key_value, 416 /// MyType::translate_key_value,
412 /// Option<(PyBytes, PyBytes)> 417 /// Option<(PyBytes, PyBytes)>
413 /// ); 418 /// );
414 /// ``` 419 /// ```