Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-cpython/src/ref_sharing.rs @ 42855:8db8fa1de2ef
rust-cpython: introduce restricted variant of RefCell
This should catch invalid borrow_mut() calls. Still the ref-sharing
interface is unsafe.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 01 Sep 2019 17:37:30 +0900 |
parents | ee0f511b7a22 |
children | 8f549c46bc64 |
line wrap: on
line diff
--- a/rust/hg-cpython/src/ref_sharing.rs Sun Sep 01 17:35:14 2019 +0900 +++ b/rust/hg-cpython/src/ref_sharing.rs Sun Sep 01 17:37:30 2019 +0900 @@ -9,7 +9,7 @@ use crate::exceptions::AlreadyBorrowed; use cpython::{PyResult, Python}; -use std::cell::{Cell, RefCell, RefMut}; +use std::cell::{Cell, Ref, RefCell, RefMut}; /// Manages the shared state between Python and Rust #[derive(Default)] @@ -61,7 +61,7 @@ pub fn leak_immutable<T>( &self, py: Python, - data: &RefCell<T>, + data: &PySharedRefCell<T>, ) -> PyResult<&'static T> { if self.mutably_borrowed.get() { return Err(AlreadyBorrowed::new( @@ -84,6 +84,38 @@ } } +/// `RefCell` wrapper to be safely used in conjunction with `PySharedState`. +/// +/// Only immutable operation is allowed through this interface. +#[derive(Debug)] +pub struct PySharedRefCell<T> { + inner: RefCell<T>, +} + +impl<T> PySharedRefCell<T> { + pub const fn new(value: T) -> PySharedRefCell<T> { + Self { + inner: RefCell::new(value), + } + } + + pub fn borrow(&self) -> Ref<T> { + // py_shared_state isn't involved since + // - inner.borrow() would fail if self is mutably borrowed, + // - and inner.borrow_mut() would fail while self is borrowed. + self.inner.borrow() + } + + pub fn as_ptr(&self) -> *mut T { + self.inner.as_ptr() + } + + pub unsafe fn borrow_mut(&self) -> RefMut<T> { + // must be borrowed by self.py_shared_state(py).borrow_mut(). + self.inner.borrow_mut() + } +} + /// Holds a mutable reference to data shared between Python and Rust. pub struct PyRefMut<'a, T> { inner: RefMut<'a, T>, @@ -158,7 +190,7 @@ /// } /// /// py_class!(pub class MyType |py| { -/// data inner: RefCell<MyStruct>; +/// data inner: PySharedRefCell<MyStruct>; /// data py_shared_state: PySharedState; /// }); /// @@ -177,16 +209,21 @@ py: Python<'a>, ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>> { + // assert $data_member type + use crate::ref_sharing::PySharedRefCell; + let data: &PySharedRefCell<_> = self.$data_member(py); self.py_shared_state(py) - .borrow_mut(py, self.$data_member(py).borrow_mut()) + .borrow_mut(py, unsafe { data.borrow_mut() }) } fn leak_immutable<'a>( &'a self, py: Python<'a>, ) -> PyResult<&'static $inner_struct> { - self.py_shared_state(py) - .leak_immutable(py, self.$data_member(py)) + // assert $data_member type + use crate::ref_sharing::PySharedRefCell; + let data: &PySharedRefCell<_> = self.$data_member(py); + self.py_shared_state(py).leak_immutable(py, data) } } @@ -295,7 +332,7 @@ /// } /// /// py_class!(pub class MyType |py| { -/// data inner: RefCell<MyStruct>; +/// data inner: PySharedRefCell<MyStruct>; /// data py_shared_state: PySharedState; /// /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {