##// 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 use crate::exceptions::AlreadyBorrowed;
25 use crate::exceptions::AlreadyBorrowed;
26 use cpython::{PyClone, PyObject, PyResult, Python};
26 use cpython::{PyClone, PyObject, PyResult, Python};
27 use std::cell::{Cell, Ref, RefCell, RefMut};
27 use std::cell::{Cell, Ref, RefCell, RefMut};
28 use std::ops::{Deref, DerefMut};
28
29
29 /// Manages the shared state between Python and Rust
30 /// Manages the shared state between Python and Rust
30 #[derive(Debug, Default)]
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 /// Immutably borrows the wrapped value.
337 pub fn get_ref<'a>(&'a self, _py: Python<'a>) -> &'a T {
338 pub fn try_borrow<'a>(
338 self.data.as_ref().unwrap()
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 /// Typically `T` is an iterator. If `T` is an immutable reference,
350 /// Typically `T` is an iterator. If `T` is an immutable reference,
344 /// `get_mut()` is useless since the inner value can't be mutated.
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 {
352 pub fn try_borrow_mut<'a>(
346 self.data.as_mut().unwrap()
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 /// Converts the inner value by the given function.
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 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
439 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
393 ///
440 ///
394 /// TODO: this is a bit awkward to use, and a better (more complicated)
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 def __next__(&self) -> PyResult<$success_type> {
504 def __next__(&self) -> PyResult<$success_type> {
458 let mut inner_opt = self.inner(py).borrow_mut();
505 let mut inner_opt = self.inner(py).borrow_mut();
459 if let Some(leaked) = inner_opt.as_mut() {
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 None => {
509 None => {
462 // replace Some(inner) by None, drop $leaked
510 // replace Some(inner) by None, drop $leaked
463 inner_opt.take();
511 inner_opt.take();
@@ -512,6 +560,28 b' mod test {'
512 }
560 }
513
561
514 #[test]
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 fn test_borrow_mut_while_leaked() {
585 fn test_borrow_mut_while_leaked() {
516 let (gil, owner) = prepare_env();
586 let (gil, owner) = prepare_env();
517 let py = gil.python();
587 let py = gil.python();
General Comments 0
You need to be logged in to leave comments. Login now