Mercurial > hg
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 /// ``` |