228 state: &'py PySharedState, |
228 state: &'py PySharedState, |
229 data: &'py RwLock<T>, // TODO perhaps this needs Pin |
229 data: &'py RwLock<T>, // TODO perhaps this needs Pin |
230 } |
230 } |
231 |
231 |
232 impl<'py, T: ?Sized> PySharedRef<'py, T> { |
232 impl<'py, T: ?Sized> PySharedRef<'py, T> { |
233 /// Immutably borrows the wrapped value. |
233 /// Take the lock on the wrapped value for read-only operations. |
234 /// |
234 /// |
235 /// # Panics |
235 /// # Panics |
236 /// |
236 /// |
237 /// Panics if the value is currently mutably borrowed. |
237 /// Panics if the lock is currently held for write operations. |
238 pub fn borrow(&self) -> RwLockReadGuard<'py, T> { |
238 pub fn read(&self) -> RwLockReadGuard<'py, T> { |
239 self.try_borrow().expect("already mutably borrowed") |
239 self.try_read().expect("already mutably borrowed") |
240 } |
240 } |
241 |
241 |
242 /// Immutably borrows the wrapped value, returning an error if the value |
242 /// Immutably borrows the wrapped value, returning an error if the value |
243 /// is currently mutably borrowed. |
243 /// is currently mutably borrowed. |
244 pub fn try_borrow(&self) -> TryLockResult<RwLockReadGuard<'py, T>> { |
244 pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'py, T>> { |
245 // state isn't involved since |
245 // state isn't involved since |
246 // - data.try_borrow() would fail if self is mutably borrowed, |
246 // - data.try_read() would fail if self is mutably borrowed, |
247 // - and data.try_borrow_mut() would fail while self is borrowed. |
247 // - and data.try_write() would fail while self is borrowed. |
248 self.data.try_read() |
248 self.data.try_read() |
249 } |
249 } |
250 |
250 |
251 /// Mutably borrows the wrapped value. |
251 /// Take the lock on the wrapped value for write operations. |
252 /// |
252 /// |
253 /// Any existing leaked references will be invalidated. |
253 /// Any existing leaked references will be invalidated. |
254 /// |
254 /// |
255 /// # Panics |
255 /// # Panics |
256 /// |
256 /// |
257 /// Panics if the value is currently borrowed. |
257 /// Panics if the lock is currently held. |
258 pub fn borrow_mut(&self) -> RwLockWriteGuard<'py, T> { |
258 pub fn write(&self) -> RwLockWriteGuard<'py, T> { |
259 self.try_borrow_mut().expect("already borrowed") |
259 self.try_write().expect("already borrowed") |
260 } |
260 } |
261 |
261 |
262 /// Mutably borrows the wrapped value, returning an error if the value |
262 /// Mutably borrows the wrapped value, returning an error if the value |
263 /// is currently borrowed. |
263 /// is currently borrowed. |
264 pub fn try_borrow_mut(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> { |
264 pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> { |
265 // the value may be immutably borrowed through UnsafePyLeaked |
265 // the value may be immutably borrowed through UnsafePyLeaked |
266 if self.state.current_borrow_count(self.py()) > 0 { |
266 if self.state.current_borrow_count(self.py()) > 0 { |
267 // propagate borrow-by-leaked state to data to get BorrowMutError |
267 // propagate borrow-by-leaked state to data to get BorrowMutError |
268 let _dummy = self.data.read(); |
268 let _dummy = self.data.read(); |
269 let _unused = self.data.try_write()?; |
269 let _unused = self.data.try_write()?; |
289 pub fn try_leak_immutable( |
289 pub fn try_leak_immutable( |
290 &self, |
290 &self, |
291 ) -> Result<UnsafePyLeaked<&'static T>, TryLeakError> { |
291 ) -> Result<UnsafePyLeaked<&'static T>, TryLeakError> { |
292 // make sure self.data isn't mutably borrowed; otherwise the |
292 // make sure self.data isn't mutably borrowed; otherwise the |
293 // generation number wouldn't be trusted. |
293 // generation number wouldn't be trusted. |
294 let data_ref = self.try_borrow()?; |
294 let data_ref = self.try_read()?; |
295 |
295 |
296 // keep reference to the owner so the data and state are alive, |
296 // keep reference to the owner so the data and state are alive, |
297 // but the data pointer can be invalidated by borrow_mut(). |
297 // but the data pointer can be invalidated by write(). |
298 // the state wouldn't since it is immutable. |
298 // the state wouldn't since it is immutable. |
299 let state_ptr: *const PySharedState = self.state; |
299 let state_ptr: *const PySharedState = self.state; |
300 let data_ptr: *const T = &*data_ref; |
300 let data_ptr: *const T = &*data_ref; |
301 Ok(UnsafePyLeaked::<&'static T> { |
301 Ok(UnsafePyLeaked::<&'static T> { |
302 owner: self.owner.clone().unbind(), |
302 owner: self.owner.clone().unbind(), |
320 /// `PySharedState` is owned by `PySharedRefCell`, and is shared across its |
320 /// `PySharedState` is owned by `PySharedRefCell`, and is shared across its |
321 /// derived references. The consistency of these references are guaranteed |
321 /// derived references. The consistency of these references are guaranteed |
322 /// as follows: |
322 /// as follows: |
323 /// |
323 /// |
324 /// - The immutability of `PycCass` object fields. Any mutation of |
324 /// - The immutability of `PycCass` object fields. Any mutation of |
325 /// [`PySharedRefCell`] is allowed only through its `borrow_mut()`. |
325 /// [`PySharedRefCell`] is allowed only through its `write()`. |
326 /// - The `py: Python<'_>` token, which makes sure that any data access is |
326 /// - The `py: Python<'_>` token, which makes sure that any data access is |
327 /// synchronized by the GIL. |
327 /// synchronized by the GIL. |
328 /// - The underlying `RefCell`, which prevents `PySharedRefCell` value from |
328 /// - The underlying `RefCell`, which prevents `PySharedRefCell` value from |
329 /// being directly borrowed or leaked while it is mutably borrowed. |
329 /// being directly borrowed or leaked while it is mutably borrowed. |
330 /// - The `borrow_count`, which is the number of references borrowed from |
330 /// - The `borrow_count`, which is the number of references borrowed from |
331 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while |
331 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while |
332 /// `UnsafePyLeaked` is borrowed. |
332 /// `UnsafePyLeaked` is borrowed. |
333 /// - The `generation` counter, which increments on `borrow_mut()`. |
333 /// - The `generation` counter, which increments on `write()`. `UnsafePyLeaked` |
334 /// `UnsafePyLeaked` reference is valid only if the `current_generation()` |
334 /// reference is valid only if the `current_generation()` equals to the |
335 /// equals to the `generation` at the time of `leak_immutable()`. |
335 /// `generation` at the time of `leak_immutable()`. |
336 #[derive(Debug)] |
336 #[derive(Debug)] |
337 struct PySharedState { |
337 struct PySharedState { |
338 // The counter variable could be Cell<usize> since any operation on |
338 // The counter variable could be Cell<usize> since any operation on |
339 // PySharedState is synchronized by the GIL, but being "atomic" makes |
339 // PySharedState is synchronized by the GIL, but being "atomic" makes |
340 // PySharedState inherently Sync. The ordering requirement doesn't |
340 // PySharedState inherently Sync. The ordering requirement doesn't |