##// END OF EJS Templates
rust-cpython: add stub wrapper that'll prevent leaked data from being mutated...
Yuya Nishihara -
r43604:945d4dba default
parent child Browse files
Show More
@@ -25,6 +25,7 b''
25 25 use crate::exceptions::AlreadyBorrowed;
26 26 use cpython::{PyClone, PyObject, PyResult, Python};
27 27 use std::cell::{Cell, Ref, RefCell, RefMut};
28 use std::ops::{Deref, DerefMut};
28 29
29 30 /// Manages the shared state between Python and Rust
30 31 #[derive(Debug, Default)]
@@ -333,17 +334,29 b' impl<T> PyLeaked<T> {'
333 334 }
334 335 }
335 336
336 /// Returns an immutable reference to the inner value.
337 pub fn get_ref<'a>(&'a self, _py: Python<'a>) -> &'a T {
338 self.data.as_ref().unwrap()
337 /// Immutably borrows the wrapped value.
338 pub fn try_borrow<'a>(
339 &'a self,
340 py: Python<'a>,
341 ) -> PyResult<PyLeakedRef<'a, T>> {
342 Ok(PyLeakedRef {
343 _py: py,
344 data: self.data.as_ref().unwrap(),
345 })
339 346 }
340 347
341 /// Returns a mutable reference to the inner value.
348 /// Mutably borrows the wrapped value.
342 349 ///
343 350 /// Typically `T` is an iterator. If `T` is an immutable reference,
344 351 /// `get_mut()` is useless since the inner value can't be mutated.
345 pub fn get_mut<'a>(&'a mut self, _py: Python<'a>) -> &'a mut T {
346 self.data.as_mut().unwrap()
352 pub fn try_borrow_mut<'a>(
353 &'a mut self,
354 py: Python<'a>,
355 ) -> PyResult<PyLeakedRefMut<'a, T>> {
356 Ok(PyLeakedRefMut {
357 _py: py,
358 data: self.data.as_mut().unwrap(),
359 })
347 360 }
348 361
349 362 /// Converts the inner value by the given function.
@@ -389,6 +402,40 b' impl<T> Drop for PyLeaked<T> {'
389 402 }
390 403 }
391 404
405 /// Immutably borrowed reference to a leaked value.
406 pub struct PyLeakedRef<'a, T> {
407 _py: Python<'a>,
408 data: &'a T,
409 }
410
411 impl<T> Deref for PyLeakedRef<'_, T> {
412 type Target = T;
413
414 fn deref(&self) -> &T {
415 self.data
416 }
417 }
418
419 /// Mutably borrowed reference to a leaked value.
420 pub struct PyLeakedRefMut<'a, T> {
421 _py: Python<'a>,
422 data: &'a mut T,
423 }
424
425 impl<T> Deref for PyLeakedRefMut<'_, T> {
426 type Target = T;
427
428 fn deref(&self) -> &T {
429 self.data
430 }
431 }
432
433 impl<T> DerefMut for PyLeakedRefMut<'_, T> {
434 fn deref_mut(&mut self) -> &mut T {
435 self.data
436 }
437 }
438
392 439 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
393 440 ///
394 441 /// TODO: this is a bit awkward to use, and a better (more complicated)
@@ -457,7 +504,8 b' macro_rules! py_shared_iterator {'
457 504 def __next__(&self) -> PyResult<$success_type> {
458 505 let mut inner_opt = self.inner(py).borrow_mut();
459 506 if let Some(leaked) = inner_opt.as_mut() {
460 match leaked.get_mut(py).next() {
507 let mut iter = leaked.try_borrow_mut(py)?;
508 match iter.next() {
461 509 None => {
462 510 // replace Some(inner) by None, drop $leaked
463 511 inner_opt.take();
@@ -512,6 +560,28 b' mod test {'
512 560 }
513 561
514 562 #[test]
563 fn test_leaked_borrow() {
564 let (gil, owner) = prepare_env();
565 let py = gil.python();
566 let leaked = owner.string_shared(py).leak_immutable().unwrap();
567 let leaked_ref = leaked.try_borrow(py).unwrap();
568 assert_eq!(*leaked_ref, "new");
569 }
570
571 #[test]
572 fn test_leaked_borrow_mut() {
573 let (gil, owner) = prepare_env();
574 let py = gil.python();
575 let leaked = owner.string_shared(py).leak_immutable().unwrap();
576 let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
577 let mut leaked_ref = leaked_iter.try_borrow_mut(py).unwrap();
578 assert_eq!(leaked_ref.next(), Some('n'));
579 assert_eq!(leaked_ref.next(), Some('e'));
580 assert_eq!(leaked_ref.next(), Some('w'));
581 assert_eq!(leaked_ref.next(), None);
582 }
583
584 #[test]
515 585 fn test_borrow_mut_while_leaked() {
516 586 let (gil, owner) = prepare_env();
517 587 let py = gil.python();
General Comments 0
You need to be logged in to leave comments. Login now