Mercurial > public > mercurial-scm > hg
comparison rust/pyo3-sharedref/src/lib.rs @ 52610:c25d345f5aa5
rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
There were two problems with the naming:
- the PyO3 version is not based on `RefCell`. Rather than calling
this `SomethingRwLock` we decided it was best to consider this
an implementation detail. We mentioned it in the doc earlier on,
but that is merely just bringing some reassuring context to the
reader, not intended to be a needed structural explanation.
- the data is not shared: it is ready to be shared
To keep the changeset readable, we only make the very minimal changes
to the tests to make them pass, i.e., not renaming local variables
(this will be done in a later move).
author | Georges Racinet <georges.racinet@cloudcrane.io> |
---|---|
date | Sun, 15 Dec 2024 15:03:27 +0100 |
parents | d1e304025b90 |
children | 4a73eb3923ac |
comparison
equal
deleted
inserted
replaced
52609:d1e304025b90 | 52610:c25d345f5aa5 |
---|---|
45 /// iterator: since a Python object cannot hold a lifetime-bound object, | 45 /// iterator: since a Python object cannot hold a lifetime-bound object, |
46 /// `Iter<'a, T>` cannot be a data field of the Python iterator object. | 46 /// `Iter<'a, T>` cannot be a data field of the Python iterator object. |
47 /// While `&'a T` can be replaced with [`std::sync::Arc`], this is typically | 47 /// While `&'a T` can be replaced with [`std::sync::Arc`], this is typically |
48 /// not suited for more complex objects that are created from such references | 48 /// not suited for more complex objects that are created from such references |
49 /// and re-expose the lifetime on their types, such as iterators. | 49 /// and re-expose the lifetime on their types, such as iterators. |
50 /// The [`PySharedRef::leak_immutable()`] and [`UnsafePyLeaked::map()`] methods | 50 /// The [`PyShareableRef::leak_immutable()`] and [`UnsafePyLeaked::map()`] |
51 /// provide a way around this issue. | 51 /// methods provide a way around this issue. |
52 /// | 52 /// |
53 /// [`PySharedRefCell`] is [`Sync`]. It works internally with locks and | 53 /// [`PyShareable`] is [`Sync`]. It works internally with locks and |
54 /// a "generation" counter that keeps track of mutations. | 54 /// a "generation" counter that keeps track of mutations. |
55 /// | 55 /// |
56 /// [`PySharedRefCell`] is merely a data struct to be stored in its | 56 /// [`PyShareable`] is merely a data struct to be stored in its |
57 /// owner Python object. | 57 /// owner Python object. |
58 /// Any further operation will be performed through [`PySharedRef`], which is | 58 /// Any further operation will be performed through [`PyShareableRef`], which |
59 /// a lifetime-bound reference to the [`PySharedRefCell`]. | 59 /// is a lifetime-bound reference to the [`PyShareable`]. |
60 /// | 60 /// |
61 /// # Example | 61 /// # Example |
62 /// | 62 /// |
63 /// ``` | 63 /// ``` |
64 /// use pyo3::prelude::*; | 64 /// use pyo3::prelude::*; |
72 /// use std::ffi::CStr; | 72 /// use std::ffi::CStr; |
73 /// use std::vec::Vec; | 73 /// use std::vec::Vec; |
74 /// | 74 /// |
75 /// #[pyclass(sequence)] | 75 /// #[pyclass(sequence)] |
76 /// struct Set { | 76 /// struct Set { |
77 /// rust_set: PySharedRefCell<HashSet<i32>>, | 77 /// rust_set: PyShareable<HashSet<i32>>, |
78 /// } | 78 /// } |
79 /// | 79 /// |
80 /// #[pymethods] | 80 /// #[pymethods] |
81 /// impl Set { | 81 /// impl Set { |
82 /// #[new] | 82 /// #[new] |
165 /// # .expect("This example should not return an error"); | 165 /// # .expect("This example should not return an error"); |
166 /// ``` | 166 /// ``` |
167 /// | 167 /// |
168 /// The borrow rules are enforced dynamically in a similar manner to the | 168 /// The borrow rules are enforced dynamically in a similar manner to the |
169 /// Python iterator. | 169 /// Python iterator. |
170 /// | |
171 /// [`PyShareable`] is merely a data struct to be stored in a Python object. | |
172 /// Any further operation will be performed through [PyShareableRef], which is | |
173 /// a lifetime-bound reference to the [`PyShareable`]. | |
170 #[derive(Debug)] | 174 #[derive(Debug)] |
171 pub struct PySharedRefCell<T: ?Sized> { | 175 pub struct PyShareable<T: ?Sized> { |
172 state: PySharedState, | 176 state: PySharedState, |
173 data: RwLock<T>, | 177 data: RwLock<T>, |
174 } | 178 } |
175 | 179 |
176 impl<T> PySharedRefCell<T> { | 180 impl<T> PyShareable<T> { |
177 /// Borrows the shared data and its state, keeping a reference | 181 /// Borrows the shared data and its state, keeping a reference |
178 /// on the owner Python object. | 182 /// on the owner Python object. |
179 /// | 183 /// |
180 /// # Safety | 184 /// # Safety |
181 /// | 185 /// |
182 /// The `data` must be owned by the `owner`. Otherwise, calling | 186 /// The `data` must be owned by the `owner`. Otherwise, calling |
183 /// `leak_immutable()` on the shared ref would create an invalid reference. | 187 /// `leak_immutable()` on the shared ref would create an invalid reference. |
184 pub unsafe fn borrow_with_owner<'py>( | 188 pub unsafe fn borrow_with_owner<'py>( |
185 &'py self, | 189 &'py self, |
186 owner: &'py Bound<'py, PyAny>, | 190 owner: &'py Bound<'py, PyAny>, |
187 ) -> PySharedRef<'py, T> { | 191 ) -> PyShareableRef<'py, T> { |
188 PySharedRef { | 192 PyShareableRef { |
189 owner, | 193 owner, |
190 state: &self.state, | 194 state: &self.state, |
191 data: &self.data, | 195 data: &self.data, |
192 } | 196 } |
193 } | 197 } |
194 } | 198 } |
195 | 199 |
196 impl<T> From<T> for PySharedRefCell<T> { | 200 impl<T> From<T> for PyShareable<T> { |
197 fn from(value: T) -> Self { | 201 fn from(value: T) -> Self { |
198 Self { | 202 Self { |
199 state: PySharedState::new(), | 203 state: PySharedState::new(), |
200 data: value.into(), | 204 data: value.into(), |
201 } | 205 } |
218 TryLockError::WouldBlock => Self::InnerLockWouldBlock, | 222 TryLockError::WouldBlock => Self::InnerLockWouldBlock, |
219 } | 223 } |
220 } | 224 } |
221 } | 225 } |
222 | 226 |
223 /// A reference to [`PySharedRefCell`] owned by a Python object. | 227 /// A reference to [`PyShareable`] and its legit owner Python object. |
224 /// | 228 /// |
225 /// This is a lifetime-bound reference to the [`PySharedRefCell`] data field. | 229 /// This is a lifetime-bound reference to the [PyShareable] data field, |
226 pub struct PySharedRef<'py, T: 'py + ?Sized> { | 230 /// and could be created by an automatically generated accessor when |
231 /// we make one. | |
232 pub struct PyShareableRef<'py, T: 'py + ?Sized> { | |
227 owner: &'py Bound<'py, PyAny>, | 233 owner: &'py Bound<'py, PyAny>, |
228 state: &'py PySharedState, | 234 state: &'py PySharedState, |
229 data: &'py RwLock<T>, // TODO perhaps this needs Pin | 235 data: &'py RwLock<T>, // TODO perhaps this needs Pin |
230 } | 236 } |
231 | 237 |
232 impl<'py, T: ?Sized> PySharedRef<'py, T> { | 238 impl<'py, T: ?Sized> PyShareableRef<'py, T> { |
233 /// Take the lock on the wrapped value for read-only operations. | 239 /// Take the lock on the wrapped value for read-only operations. |
234 /// | 240 /// |
235 /// # Panics | 241 /// # Panics |
236 /// | 242 /// |
237 /// Panics if the lock is currently held for write operations. | 243 /// Panics if the lock is currently held for write operations. |
315 } | 321 } |
316 } | 322 } |
317 | 323 |
318 /// The shared state between Python and Rust | 324 /// The shared state between Python and Rust |
319 /// | 325 /// |
320 /// `PySharedState` is owned by `PySharedRefCell`, and is shared across its | 326 /// `PySharedState` is owned by `PyShareable`, and is shared across its |
321 /// derived references. The consistency of these references are guaranteed | 327 /// derived references. The consistency of these references are guaranteed |
322 /// as follows: | 328 /// as follows: |
323 /// | 329 /// |
324 /// - The immutability of `PycCass` object fields. Any mutation of | 330 /// - The immutability of `PycCass` object fields. Any mutation of |
325 /// [`PySharedRefCell`] is allowed only through its `write()`. | 331 /// [`PyShareable`] is allowed only through its `write()`. |
326 /// - The `py: Python<'_>` token, which makes sure that any data access is | 332 /// - The `py: Python<'_>` token, which makes sure that any data access is |
327 /// synchronized by the GIL. | 333 /// synchronized by the GIL. |
328 /// - The underlying `RefCell`, which prevents `PySharedRefCell` value from | 334 /// - The underlying `RefCell`, which prevents `PyShareable` value from being |
329 /// being directly borrowed or leaked while it is mutably borrowed. | 335 /// directly borrowed or leaked while it is mutably borrowed. |
330 /// - The `borrow_count`, which is the number of references borrowed from | 336 /// - The `borrow_count`, which is the number of references borrowed from |
331 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while | 337 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while |
332 /// `UnsafePyLeaked` is borrowed. | 338 /// `UnsafePyLeaked` is borrowed. |
333 /// - The `generation` counter, which increments on `write()`. `UnsafePyLeaked` | 339 /// - The `generation` counter, which increments on `write()`. `UnsafePyLeaked` |
334 /// reference is valid only if the `current_generation()` equals to the | 340 /// reference is valid only if the `current_generation()` equals to the |
380 self.generation.fetch_add(1, Ordering::Relaxed); | 386 self.generation.fetch_add(1, Ordering::Relaxed); |
381 } | 387 } |
382 } | 388 } |
383 | 389 |
384 /// Helper to keep the borrow count updated while the shared object is | 390 /// Helper to keep the borrow count updated while the shared object is |
385 /// immutably borrowed without using the `RefCell` interface. | 391 /// immutably borrowed without using the `RwLock` interface. |
386 struct BorrowPyShared<'a> { | 392 struct BorrowPyShared<'a> { |
387 py: Python<'a>, | 393 py: Python<'a>, |
388 state: &'a PySharedState, | 394 state: &'a PySharedState, |
389 } | 395 } |
390 | 396 |
399 fn drop(&mut self) { | 405 fn drop(&mut self) { |
400 self.state.decrease_borrow_count(self.py); | 406 self.state.decrease_borrow_count(self.py); |
401 } | 407 } |
402 } | 408 } |
403 | 409 |
404 /// An immutable reference to [`PySharedRefCell`] value, not bound to lifetime. | 410 /// An immutable reference to [`PyShareable`] value, not bound to lifetime. |
405 /// | 411 /// |
406 /// The reference will be invalidated once the original value is mutably | 412 /// The reference will be invalidated once the original value is mutably |
407 /// borrowed. | 413 /// borrowed. |
408 /// | 414 /// |
409 /// # Safety | 415 /// # Safety |