use core::cell::UnsafeCell; use core::fmt; use core::mem::{self, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr::{self, NonNull}; use alloc::sync::Arc; pub(crate) mod futures; mod raw; use self::futures::{ Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc, }; use self::raw::{RawRwLock, RawUpgrade}; /// An async reader-writer lock. /// /// This type of lock allows multiple readers or one writer at any point in time. /// /// The locking strategy is write-preferring, which means writers are never starved. /// Releasing a write lock wakes the next blocked reader and the next blocked writer. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let lock = RwLock::new(5); /// /// // Multiple read locks can be held at a time. /// let r1 = lock.read().await; /// let r2 = lock.read().await; /// assert_eq!(*r1, 5); /// assert_eq!(*r2, 5); /// drop((r1, r2)); /// /// // Only one write lock can be held at a time. /// let mut w = lock.write().await; /// *w += 1; /// assert_eq!(*w, 6); /// # }) /// ``` pub struct RwLock { /// The underlying locking implementation. /// Doesn't depend on `T`. raw: RawRwLock, /// The inner value. value: UnsafeCell, } unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} impl RwLock { const_fn! { const_if: #[cfg(not(loom))]; /// Creates a new reader-writer lock. /// /// # Examples /// /// ``` /// use async_lock::RwLock; /// /// let lock = RwLock::new(0); /// ``` #[must_use] #[inline] pub const fn new(t: T) -> RwLock { RwLock { raw: RawRwLock::new(), value: UnsafeCell::new(t), } } } /// Unwraps the lock and returns the inner value. /// /// # Examples /// /// ``` /// use async_lock::RwLock; /// /// let lock = RwLock::new(5); /// assert_eq!(lock.into_inner(), 5); /// ``` #[must_use] #[inline] pub fn into_inner(self) -> T { self.value.into_inner() } /// Attempts to acquire an an owned, reference-counted read lock. /// /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.read_arc().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read_arc().is_some()); /// # }) /// ``` #[inline] pub fn try_read_arc(self: &Arc) -> Option> { if self.raw.try_read() { let arc = self.clone(); // SAFETY: we previously acquired a read lock. Some(unsafe { RwLockReadGuardArc::from_arc(arc) }) } else { None } } /// Acquires an owned, reference-counted read lock. /// /// Returns a guard that releases the lock when dropped. /// /// Note that attempts to acquire a read lock will block if there are also concurrent attempts /// to acquire a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.read_arc().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read_arc().is_some()); /// # }) /// ``` #[inline] pub fn read_arc<'a>(self: &'a Arc) -> ReadArc<'a, T> { ReadArc::new(self.raw.read(), self) } /// Acquires an owned, reference-counted read lock. /// /// Returns a guard that releases the lock when dropped. /// /// Note that attempts to acquire a read lock will block if there are also concurrent attempts /// to acquire a write lock. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`read_arc`][`RwLock::read_arc`] method, /// this method will block the current thread until the read lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.read_arc_blocking(); /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read().is_some()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn read_arc_blocking(self: &Arc) -> RwLockReadGuardArc { self.read_arc().wait() } } impl RwLock { /// Attempts to acquire a read lock. /// /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// let reader = lock.read().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read().is_some()); /// # }) /// ``` #[inline] pub fn try_read(&self) -> Option> { if self.raw.try_read() { Some(RwLockReadGuard { lock: &self.raw, value: self.value.get(), }) } else { None } } /// Acquires a read lock. /// /// Returns a guard that releases the lock when dropped. /// /// Note that attempts to acquire a read lock will block if there are also concurrent attempts /// to acquire a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// let reader = lock.read().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read().is_some()); /// # }) /// ``` #[inline] pub fn read(&self) -> Read<'_, T> { Read::new(self.raw.read(), self.value.get()) } /// Acquires a read lock. /// /// Returns a guard that releases the lock when dropped. /// /// Note that attempts to acquire a read lock will block if there are also concurrent attempts /// to acquire a write lock. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`read`][`RwLock::read`] method, /// this method will block the current thread until the read lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// let reader = lock.read_blocking(); /// assert_eq!(*reader, 1); /// /// assert!(lock.try_read().is_some()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn read_blocking(&self) -> RwLockReadGuard<'_, T> { self.read().wait() } /// Attempts to acquire a read lock with the possibility to upgrade to a write lock. /// /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read().await; /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn try_upgradable_read(&self) -> Option> { if self.raw.try_upgradable_read() { Some(RwLockUpgradableReadGuard { lock: &self.raw, value: self.value.get(), }) } else { None } } /// Acquires a read lock with the possibility to upgrade to a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// Note that attempts to acquire an upgradable read lock will block if there are concurrent /// attempts to acquire another upgradable read lock or a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read().await; /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn upgradable_read(&self) -> UpgradableRead<'_, T> { UpgradableRead::new(self.raw.upgradable_read(), self.value.get()) } /// Attempts to acquire a read lock with the possibility to upgrade to a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// Note that attempts to acquire an upgradable read lock will block if there are concurrent /// attempts to acquire another upgradable read lock or a write lock. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`upgradable_read`][`RwLock::upgradable_read`] /// method, this method will block the current thread until the read lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read_blocking(); /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuard::upgrade_blocking(reader); /// *writer = 2; /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn upgradable_read_blocking(&self) -> RwLockUpgradableReadGuard<'_, T> { self.upgradable_read().wait() } /// Attempts to acquire an owned, reference-counted read lock /// with the possibility to upgrade to a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// Note that attempts to acquire an upgradable read lock will block if there are concurrent /// attempts to acquire another upgradable read lock or a write lock. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`upgradable_read_arc`][`RwLock::upgradable_read_arc`] /// method, this method will block the current thread until the read lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc_blocking(); /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuardArc::upgrade_blocking(reader); /// *writer = 2; /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn upgradable_read_arc_blocking(self: &Arc) -> RwLockUpgradableReadGuardArc { self.upgradable_read_arc().wait() } /// Attempts to acquire an owned, reference-counted read lock with the possibility to /// upgrade to a write lock. /// /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read_arc().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn try_upgradable_read_arc(self: &Arc) -> Option> { if self.raw.try_upgradable_read() { Some(RwLockUpgradableReadGuardArc { lock: self.clone() }) } else { None } } /// Acquires an owned, reference-counted read lock with the possibility /// to upgrade to a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there /// can be at most one upgradable read lock at a time. /// /// Note that attempts to acquire an upgradable read lock will block if there are concurrent /// attempts to acquire another upgradable read lock or a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read_arc().unwrap(), 1); /// /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn upgradable_read_arc<'a>(self: &'a Arc) -> UpgradableReadArc<'a, T> { UpgradableReadArc::new(self.raw.upgradable_read(), self) } /// Attempts to acquire a write lock. /// /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// assert!(lock.try_write().is_some()); /// let reader = lock.read().await; /// assert!(lock.try_write().is_none()); /// # }) /// ``` #[inline] pub fn try_write(&self) -> Option> { if self.raw.try_write() { Some(RwLockWriteGuard { lock: &self.raw, value: self.value.get(), }) } else { None } } /// Acquires a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// let writer = lock.write().await; /// assert!(lock.try_read().is_none()); /// # }) /// ``` #[inline] pub fn write(&self) -> Write<'_, T> { Write::new(self.raw.write(), self.value.get()) } /// Acquires a write lock. /// /// Returns a guard that releases the lock when dropped. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`write`] method, this method will /// block the current thread until the write lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use async_lock::RwLock; /// /// let lock = RwLock::new(1); /// /// let writer = lock.write_blocking(); /// assert!(lock.try_read().is_none()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn write_blocking(&self) -> RwLockWriteGuard<'_, T> { self.write().wait() } /// Attempts to acquire an owned, reference-counted write lock. /// /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a /// guard is returned that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// assert!(lock.try_write_arc().is_some()); /// let reader = lock.read_arc().await; /// assert!(lock.try_write_arc().is_none()); /// # }) /// ``` #[inline] pub fn try_write_arc(self: &Arc) -> Option> { if self.raw.try_write() { Some(RwLockWriteGuardArc { lock: self.clone() }) } else { None } } /// Acquires an owned, reference-counted write lock. /// /// Returns a guard that releases the lock when dropped. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let writer = lock.write_arc().await; /// assert!(lock.try_read_arc().is_none()); /// # }) /// ``` #[inline] pub fn write_arc<'a>(self: &'a Arc) -> WriteArc<'a, T> { WriteArc::new(self.raw.write(), self) } /// Acquires an owned, reference-counted write lock. /// /// Returns a guard that releases the lock when dropped. /// /// # Blocking /// /// Rather than using asynchronous waiting, like the [`write_arc`][RwLock::write_arc] method, this method will /// block the current thread until the write lock is acquired. /// /// This method should not be used in an asynchronous context. It is intended to be /// used in a way that a lock can be used in both asynchronous and synchronous contexts. /// Calling this method in an asynchronous context may result in a deadlock. /// /// # Examples /// /// ``` /// use std::sync::Arc; /// use async_lock::RwLock; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let writer = lock.write_arc_blocking(); /// assert!(lock.try_read().is_none()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn write_arc_blocking(self: &Arc) -> RwLockWriteGuardArc { self.write_arc().wait() } /// Returns a mutable reference to the inner value. /// /// Since this call borrows the lock mutably, no actual locking takes place. The mutable borrow /// statically guarantees no locks exist. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::RwLock; /// /// let mut lock = RwLock::new(1); /// /// *lock.get_mut() = 2; /// assert_eq!(*lock.read().await, 2); /// # }) /// ``` #[must_use] #[inline] pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *self.value.get() } } } impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct Locked; impl fmt::Debug for Locked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("") } } match self.try_read() { None => f.debug_struct("RwLock").field("value", &Locked).finish(), Some(guard) => f.debug_struct("RwLock").field("value", &&*guard).finish(), } } } impl From for RwLock { #[inline] fn from(val: T) -> RwLock { RwLock::new(val) } } impl Default for RwLock { #[inline] fn default() -> RwLock { RwLock::new(Default::default()) } } /// A guard that releases the read lock when dropped. #[clippy::has_significant_drop] pub struct RwLockReadGuard<'a, T: ?Sized> { /// Reference to underlying locking implementation. /// Doesn't depend on `T`. lock: &'a RawRwLock, /// Pointer to the value protected by the lock. Covariant in `T`. value: *const T, } unsafe impl Send for RwLockReadGuard<'_, T> {} unsafe impl Sync for RwLockReadGuard<'_, T> {} impl Drop for RwLockReadGuard<'_, T> { #[inline] fn drop(&mut self) { // SAFETY: we are dropping a read guard. unsafe { self.lock.read_unlock(); } } } impl fmt::Debug for RwLockReadGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockReadGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockReadGuard<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*self.value } } } /// An owned, reference-counting guard that releases the read lock when dropped. #[clippy::has_significant_drop] pub struct RwLockReadGuardArc { /// **WARNING**: This doesn't actually point to a `T`! /// It points to a `RwLock`, via a pointer obtained with `Arc::into_raw`. /// We lie for covariance. lock: NonNull, } unsafe impl Send for RwLockReadGuardArc {} unsafe impl Sync for RwLockReadGuardArc {} impl RwLockReadGuardArc { /// Constructs the underlying `Arc` back from the underlying `RwLock`. /// /// # Safety /// /// Both the returned `Arc` and the guard will decrement their reference /// counts on drop! So one of the two must be forgotten. #[inline] unsafe fn inner_arc(guard: &Self) -> ManuallyDrop>> { ManuallyDrop::new(Arc::from_raw(guard.lock.as_ptr().cast())) } /// Constructs a guard from the underlying `Arc`. /// /// # Safety /// /// A read lock must be acquired before calling this. #[inline] unsafe fn from_arc(arc: Arc>) -> Self { let ptr = Arc::into_raw(arc); Self { lock: NonNull::new(ptr as *mut RwLock as *mut T).unwrap(), } } } impl Drop for RwLockReadGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are in `drop`, decrementing the reference count // on purpose. // We hold a read lock on the `RwLock`. unsafe { let arc = ManuallyDrop::into_inner(Self::inner_arc(self)); arc.raw.read_unlock(); } } } impl fmt::Debug for RwLockReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockReadGuardArc { type Target = T; #[inline] fn deref(&self) -> &T { // SAFETY: we use `ManuallyDrop` to avoid double-drop. // We hold a read lock on the `RwLock`. unsafe { let arc = Self::inner_arc(self); &*arc.value.get() } } } /// A guard that releases the upgradable read lock when dropped. #[clippy::has_significant_drop] pub struct RwLockUpgradableReadGuard<'a, T: ?Sized> { /// Reference to underlying locking implementation. /// Doesn't depend on `T`. /// This guard holds a lock on the witer mutex! lock: &'a RawRwLock, /// Pointer to the value protected by the lock. Invariant in `T` /// as the upgradable lock could provide write access. value: *mut T, } impl Drop for RwLockUpgradableReadGuard<'_, T> { #[inline] fn drop(&mut self) { // SAFETY: we are dropping an upgradable read guard. unsafe { self.lock.upgradable_read_unlock(); } } } unsafe impl Send for RwLockUpgradableReadGuard<'_, T> {} unsafe impl Sync for RwLockUpgradableReadGuard<'_, T> {} impl<'a, T: ?Sized> RwLockUpgradableReadGuard<'a, T> { /// Downgrades into a regular reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_upgradable_read().is_none()); /// /// let reader = RwLockUpgradableReadGuard::downgrade(reader); /// /// assert!(lock.try_upgradable_read().is_some()); /// # }) /// ``` #[inline] pub fn downgrade(guard: Self) -> RwLockReadGuard<'a, T> { let upgradable = ManuallyDrop::new(guard); // SAFETY: `guard` is an upgradable read lock. unsafe { upgradable.lock.downgrade_upgradable_read(); }; RwLockReadGuard { lock: upgradable.lock, value: upgradable.value, } } /// Attempts to upgrade into a write lock. /// /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, /// an upgraded guard is returned that releases the write lock when dropped. /// /// This function can only fail if there are other active read locks. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read().await; /// assert_eq!(*reader, 1); /// /// let reader2 = lock.read().await; /// let reader = RwLockUpgradableReadGuard::try_upgrade(reader).unwrap_err(); /// /// drop(reader2); /// let writer = RwLockUpgradableReadGuard::try_upgrade(reader).unwrap(); /// # }) /// ``` #[inline] pub fn try_upgrade(guard: Self) -> Result, Self> { // If there are no readers, grab the write lock. // SAFETY: `guard` is an upgradable read guard if unsafe { guard.lock.try_upgrade() } { let reader = ManuallyDrop::new(guard); Ok(RwLockWriteGuard { lock: reader.lock, value: reader.value, }) } else { Err(guard) } } /// Upgrades into a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read().await; /// assert_eq!(*reader, 1); /// /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn upgrade(guard: Self) -> Upgrade<'a, T> { let reader = ManuallyDrop::new(guard); Upgrade::new( // SAFETY: `reader` is an upgradable read guard unsafe { reader.lock.upgrade() }, reader.value, ) } /// Upgrades into a write lock. /// /// # Blocking /// /// This function will block the current thread until it is able to acquire the write lock. /// /// # Examples /// /// ``` /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; /// /// let lock = RwLock::new(1); /// /// let reader = lock.upgradable_read_blocking(); /// assert_eq!(*reader, 1); /// /// let mut writer = RwLockUpgradableReadGuard::upgrade_blocking(reader); /// *writer = 2; /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn upgrade_blocking(guard: Self) -> RwLockWriteGuard<'a, T> { RwLockUpgradableReadGuard::upgrade(guard).wait() } } impl fmt::Debug for RwLockUpgradableReadGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockUpgradableReadGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockUpgradableReadGuard<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*self.value } } } /// An owned, reference-counting guard that releases the upgradable read lock when dropped. #[clippy::has_significant_drop] pub struct RwLockUpgradableReadGuardArc { /// We want invariance, so no need for pointer tricks. lock: Arc>, } impl Drop for RwLockUpgradableReadGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are dropping an upgradable read guard. unsafe { self.lock.raw.upgradable_read_unlock(); } } } unsafe impl Send for RwLockUpgradableReadGuardArc {} unsafe impl Sync for RwLockUpgradableReadGuardArc {} impl fmt::Debug for RwLockUpgradableReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockUpgradableReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockUpgradableReadGuardArc { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*self.lock.value.get() } } } impl RwLockUpgradableReadGuardArc { /// Downgrades into a regular reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// /// assert!(lock.try_upgradable_read_arc().is_none()); /// /// let reader = RwLockUpgradableReadGuardArc::downgrade(reader); /// /// assert!(lock.try_upgradable_read_arc().is_some()); /// # }) /// ``` #[inline] pub fn downgrade(guard: Self) -> RwLockReadGuardArc { // SAFETY: we hold an upgradable read lock, which we are downgrading. unsafe { guard.lock.raw.downgrade_upgradable_read(); } // SAFETY: we just downgraded to a read lock. unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } } } impl RwLockUpgradableReadGuardArc { /// Consumes the lock (without dropping) and returns the underlying `Arc`. #[inline] fn into_arc(guard: Self) -> Arc> { let guard = ManuallyDrop::new(guard); // SAFETY: `guard` is not used after this unsafe { ptr::read(&guard.lock) } } /// Attempts to upgrade into a write lock. /// /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, /// an upgraded guard is returned that releases the write lock when dropped. /// /// This function can only fail if there are other active read locks. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// /// let reader2 = lock.read_arc().await; /// let reader = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap_err(); /// /// drop(reader2); /// let writer = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap(); /// # }) /// ``` #[inline] pub fn try_upgrade(guard: Self) -> Result, Self> { // SAFETY: We hold an upgradable read guard. if unsafe { guard.lock.raw.try_upgrade() } { Ok(RwLockWriteGuardArc { lock: Self::into_arc(guard), }) } else { Err(guard) } } /// Upgrades into a write lock. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] pub fn upgrade(guard: Self) -> UpgradeArc { // We need to do some ugly lying about lifetimes; // See the comment on the `raw` field of `ArcUpgrade` // for an explanation. // SAFETY: we hold an upgradable read guard. let raw: RawUpgrade<'_> = unsafe { guard.lock.raw.upgrade() }; // SAFETY: see above explanation. let raw: RawUpgrade<'static> = unsafe { mem::transmute(raw) }; unsafe { UpgradeArc::new( ManuallyDrop::new(raw), ManuallyDrop::new(Self::into_arc(guard)), ) } } /// Upgrades into a write lock. /// /// # Blocking /// /// This function will block the current thread until it is able to acquire the write lock. /// /// # Examples /// /// ``` /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc_blocking(); /// assert_eq!(*reader, 1); /// /// let mut writer = RwLockUpgradableReadGuardArc::upgrade_blocking(reader); /// *writer = 2; /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] #[inline] pub fn upgrade_blocking(guard: Self) -> RwLockWriteGuardArc { RwLockUpgradableReadGuardArc::upgrade(guard).wait() } } /// A guard that releases the write lock when dropped. #[clippy::has_significant_drop] pub struct RwLockWriteGuard<'a, T: ?Sized> { /// Reference to underlying locking implementation. /// Doesn't depend on `T`. /// This guard holds a lock on the witer mutex! lock: &'a RawRwLock, /// Pointer to the value protected by the lock. Invariant in `T`. value: *mut T, } unsafe impl Send for RwLockWriteGuard<'_, T> {} unsafe impl Sync for RwLockWriteGuard<'_, T> {} impl Drop for RwLockWriteGuard<'_, T> { #[inline] fn drop(&mut self) { // SAFETY: we are dropping a write lock unsafe { self.lock.write_unlock(); } } } impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// Downgrades into a regular reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockWriteGuard}; /// /// let lock = RwLock::new(1); /// /// let mut writer = lock.write().await; /// *writer += 1; /// /// assert!(lock.try_read().is_none()); /// /// let reader = RwLockWriteGuard::downgrade(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_read().is_some()); /// # }) /// ``` #[inline] pub fn downgrade(guard: Self) -> RwLockReadGuard<'a, T> { let write = ManuallyDrop::new(guard); // SAFETY: `write` is a write guard unsafe { write.lock.downgrade_write(); } RwLockReadGuard { lock: write.lock, value: write.value, } } /// Downgrades into an upgradable reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use async_lock::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}; /// /// let lock = RwLock::new(1); /// /// let mut writer = lock.write().await; /// *writer += 1; /// /// assert!(lock.try_read().is_none()); /// /// let reader = RwLockWriteGuard::downgrade_to_upgradable(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_write().is_none()); /// assert!(lock.try_read().is_some()); /// /// assert!(RwLockUpgradableReadGuard::try_upgrade(reader).is_ok()) /// # }) /// ``` #[inline] pub fn downgrade_to_upgradable(guard: Self) -> RwLockUpgradableReadGuard<'a, T> { let write = ManuallyDrop::new(guard); // SAFETY: `write` is a write guard unsafe { write.lock.downgrade_to_upgradable(); } RwLockUpgradableReadGuard { lock: write.lock, value: write.value, } } } impl fmt::Debug for RwLockWriteGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockWriteGuard<'_, T> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockWriteGuard<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*self.value } } } impl DerefMut for RwLockWriteGuard<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.value } } } /// An owned, reference-counted guard that releases the write lock when dropped. #[clippy::has_significant_drop] pub struct RwLockWriteGuardArc { lock: Arc>, } unsafe impl Send for RwLockWriteGuardArc {} unsafe impl Sync for RwLockWriteGuardArc {} impl Drop for RwLockWriteGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are dropping a write lock. unsafe { self.lock.raw.write_unlock(); } } } impl RwLockWriteGuardArc { /// Downgrades into a regular reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockWriteGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let mut writer = lock.write_arc().await; /// *writer += 1; /// /// assert!(lock.try_read_arc().is_none()); /// /// let reader = RwLockWriteGuardArc::downgrade(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_read_arc().is_some()); /// # }) /// ``` #[inline] pub fn downgrade(guard: Self) -> RwLockReadGuardArc { // SAFETY: `write` is a write guard unsafe { guard.lock.raw.downgrade_write(); } // SAFETY: we just downgraded to a read lock unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } } } impl RwLockWriteGuardArc { /// Consumes the lock (without dropping) and returns the underlying `Arc`. #[inline] fn into_arc(guard: Self) -> Arc> { let guard = ManuallyDrop::new(guard); // SAFETY: `guard` is not used after this unsafe { ptr::read(&guard.lock) } } /// Downgrades into an upgradable reader guard. /// /// # Examples /// /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc, RwLockWriteGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let mut writer = lock.write_arc().await; /// *writer += 1; /// /// assert!(lock.try_read_arc().is_none()); /// /// let reader = RwLockWriteGuardArc::downgrade_to_upgradable(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_write_arc().is_none()); /// assert!(lock.try_read_arc().is_some()); /// /// assert!(RwLockUpgradableReadGuardArc::try_upgrade(reader).is_ok()) /// # }) /// ``` #[inline] pub fn downgrade_to_upgradable(guard: Self) -> RwLockUpgradableReadGuardArc { // SAFETY: `guard` is a write guard unsafe { guard.lock.raw.downgrade_to_upgradable(); } RwLockUpgradableReadGuardArc { lock: Self::into_arc(guard), } } } impl fmt::Debug for RwLockWriteGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockWriteGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } impl Deref for RwLockWriteGuardArc { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*self.lock.value.get() } } } impl DerefMut for RwLockWriteGuardArc { #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.lock.value.get() } } }