Mercurial > public > mercurial-scm > hg
comparison rust/hg-cpython/src/ref_sharing.rs @ 43178:1b2200bd06b6
rust-cpython: add safe wrapper representing shared data borrowed from PyObject
PySharedRef is a tempoary wrapper around PySharedRefCell. It provides safe
functions for each shared data. $shared_accessor implements a safe method
to construct PySharedRefCell.
This allows us to add more than once PySharedRefCell to a Python object.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 15 Sep 2019 16:50:48 +0900 |
parents | 5cb8867c9e2b |
children | 7d6758f2d50c |
comparison
equal
deleted
inserted
replaced
43177:5cb8867c9e2b | 43178:1b2200bd06b6 |
---|---|
123 /// | 123 /// |
124 /// Only immutable operation is allowed through this interface. | 124 /// Only immutable operation is allowed through this interface. |
125 #[derive(Debug)] | 125 #[derive(Debug)] |
126 pub struct PySharedRefCell<T> { | 126 pub struct PySharedRefCell<T> { |
127 inner: RefCell<T>, | 127 inner: RefCell<T>, |
128 pub py_shared_state: PySharedState, // TODO: remove pub | 128 py_shared_state: PySharedState, |
129 } | 129 } |
130 | 130 |
131 impl<T> PySharedRefCell<T> { | 131 impl<T> PySharedRefCell<T> { |
132 pub fn new(value: T) -> PySharedRefCell<T> { | 132 pub fn new(value: T) -> PySharedRefCell<T> { |
133 Self { | 133 Self { |
154 pub fn borrow_mut<'a>( | 154 pub fn borrow_mut<'a>( |
155 &'a self, | 155 &'a self, |
156 py: Python<'a>, | 156 py: Python<'a>, |
157 ) -> PyResult<PyRefMut<'a, T>> { | 157 ) -> PyResult<PyRefMut<'a, T>> { |
158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut()) | 158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut()) |
159 } | |
160 } | |
161 | |
162 /// Sharable data member of type `T` borrowed from the `PyObject`. | |
163 pub struct PySharedRef<'a, T> { | |
164 py: Python<'a>, | |
165 owner: &'a PyObject, | |
166 data: &'a PySharedRefCell<T>, | |
167 } | |
168 | |
169 impl<'a, T> PySharedRef<'a, T> { | |
170 /// # Safety | |
171 /// | |
172 /// The `data` must be owned by the `owner`. Otherwise, the leak count | |
173 /// would get wrong. | |
174 pub unsafe fn new( | |
175 py: Python<'a>, | |
176 owner: &'a PyObject, | |
177 data: &'a PySharedRefCell<T>, | |
178 ) -> Self { | |
179 Self { py, owner, data } | |
180 } | |
181 | |
182 pub fn borrow(&self) -> Ref<T> { | |
183 self.data.borrow() | |
184 } | |
185 | |
186 pub fn borrow_mut(&self) -> PyResult<PyRefMut<'a, T>> { | |
187 self.data.borrow_mut(self.py) | |
188 } | |
189 | |
190 /// Returns a leaked reference and its management object. | |
191 /// | |
192 /// # Safety | |
193 /// | |
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 | |
196 /// dangling reference. | |
197 pub unsafe fn leak_immutable( | |
198 &self, | |
199 ) -> PyResult<(PyLeakedRef, &'static T)> { | |
200 let (static_ref, static_state_ref) = self | |
201 .data | |
202 .py_shared_state | |
203 .leak_immutable(self.py, self.data)?; | |
204 let leak_handle = | |
205 PyLeakedRef::new(self.py, self.owner, static_state_ref); | |
206 Ok((leak_handle, static_ref)) | |
159 } | 207 } |
160 } | 208 } |
161 | 209 |
162 /// Holds a mutable reference to data shared between Python and Rust. | 210 /// Holds a mutable reference to data shared between Python and Rust. |
163 pub struct PyRefMut<'a, T> { | 211 pub struct PyRefMut<'a, T> { |
217 /// | 265 /// |
218 /// * `$name` is the same identifier used in for `py_class!` macro call. | 266 /// * `$name` is the same identifier used in for `py_class!` macro call. |
219 /// * `$inner_struct` is the identifier of the underlying Rust struct | 267 /// * `$inner_struct` is the identifier of the underlying Rust struct |
220 /// * `$data_member` is the identifier of the data member of `$inner_struct` | 268 /// * `$data_member` is the identifier of the data member of `$inner_struct` |
221 /// that will be shared. | 269 /// that will be shared. |
270 /// * `$shared_accessor` is the function name to be generated, which allows | |
271 /// safe access to the data member. | |
272 /// | |
273 /// # Safety | |
274 /// | |
275 /// `$data_member` must persist while the `$name` object is alive. In other | |
276 /// words, it must be an accessor to a data field of the Python object. | |
222 /// | 277 /// |
223 /// # Example | 278 /// # Example |
224 /// | 279 /// |
225 /// ``` | 280 /// ``` |
226 /// struct MyStruct { | 281 /// struct MyStruct { |
229 /// | 284 /// |
230 /// py_class!(pub class MyType |py| { | 285 /// py_class!(pub class MyType |py| { |
231 /// data inner: PySharedRefCell<MyStruct>; | 286 /// data inner: PySharedRefCell<MyStruct>; |
232 /// }); | 287 /// }); |
233 /// | 288 /// |
234 /// py_shared_ref!(MyType, MyStruct, inner); | 289 /// py_shared_ref!(MyType, MyStruct, inner, inner_shared); |
235 /// ``` | 290 /// ``` |
236 macro_rules! py_shared_ref { | 291 macro_rules! py_shared_ref { |
237 ( | 292 ( |
238 $name: ident, | 293 $name: ident, |
239 $inner_struct: ident, | 294 $inner_struct: ident, |
240 $data_member: ident | 295 $data_member: ident, |
296 $shared_accessor: ident | |
241 ) => { | 297 ) => { |
242 impl $name { | 298 impl $name { |
243 // TODO: remove this function in favor of inner(py).borrow_mut() | 299 /// Returns a safe reference to the shared `$data_member`. |
300 /// | |
301 /// This function guarantees that `PySharedRef` is created with | |
302 /// the valid `self` and `self.$data_member(py)` pair. | |
303 fn $shared_accessor<'a>( | |
304 &'a self, | |
305 py: Python<'a>, | |
306 ) -> $crate::ref_sharing::PySharedRef<'a, $inner_struct> { | |
307 use cpython::PythonObject; | |
308 use $crate::ref_sharing::PySharedRef; | |
309 let owner = self.as_object(); | |
310 let data = self.$data_member(py); | |
311 unsafe { PySharedRef::new(py, owner, data) } | |
312 } | |
313 | |
314 // TODO: remove this function in favor of $shared_accessor(py) | |
244 fn borrow_mut<'a>( | 315 fn borrow_mut<'a>( |
245 &'a self, | 316 &'a self, |
246 py: Python<'a>, | 317 py: Python<'a>, |
247 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>> | 318 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>> |
248 { | 319 { |
249 // assert $data_member type | 320 self.$shared_accessor(py).borrow_mut() |
250 use crate::ref_sharing::PySharedRefCell; | 321 } |
251 let data: &PySharedRefCell<_> = self.$data_member(py); | 322 |
252 data.borrow_mut(py) | 323 // TODO: remove this function in favor of $shared_accessor(py) |
253 } | |
254 | |
255 /// Returns a leaked reference and its management object. | |
256 /// | |
257 /// # Safety | |
258 /// | |
259 /// It's up to you to make sure that the management object lives | |
260 /// longer than the leaked reference. Otherwise, you'll get a | |
261 /// dangling reference. | |
262 unsafe fn leak_immutable<'a>( | 324 unsafe fn leak_immutable<'a>( |
263 &'a self, | 325 &'a self, |
264 py: Python<'a>, | 326 py: Python<'a>, |
265 ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> { | 327 ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> { |
266 use cpython::PythonObject; | 328 self.$shared_accessor(py).leak_immutable() |
267 // assert $data_member type | |
268 use crate::ref_sharing::PySharedRefCell; | |
269 let data: &PySharedRefCell<_> = self.$data_member(py); | |
270 let (static_ref, static_state_ref) = | |
271 data.py_shared_state.leak_immutable(py, data)?; | |
272 let leak_handle = | |
273 PyLeakedRef::new(py, self.as_object(), static_state_ref); | |
274 Ok((leak_handle, static_ref)) | |
275 } | 329 } |
276 } | 330 } |
277 }; | 331 }; |
278 } | 332 } |
279 | 333 |