use std::fmt::Debug;
use crate::{
implementation::{LockMetadata, SharedImpl},
synchronizer::{SynchronizerMetadata, SynchronizerReadLock, SynchronizerWriteLock},
};
unsafe impl<'a, T: ?Sized> Send for SharedReadLockInner<'a, T> {}
unsafe impl<'a, T: ?Sized> Send for SharedWriteLockInner<'a, T> {}
pub enum SharedReadLockInner<'a, T: ?Sized> {
Sync(SynchronizerReadLock<'a, LockMetadata, T>),
SyncBox(SynchronizerReadLock<'a, LockMetadata, Box<T>>),
Projection(Box<dyn std::ops::Deref<Target = T> + 'a>),
}
#[must_use = "if unused the lock will immediately unlock"]
pub struct SharedReadLock<'a, T: ?Sized> {
pub(crate) inner: SharedReadLockInner<'a, T>,
#[cfg(feature = "deadlock_detection")]
pub(crate) lockdep: Option<crate::lockdep::HeldToken>,
}
impl<'a, T: ?Sized> SharedReadLock<'a, T> {
pub(crate) fn from_projection(inner: Box<dyn std::ops::Deref<Target = T> + 'a>) -> Self {
SharedReadLock {
inner: SharedReadLockInner::Projection(inner),
#[cfg(feature = "deadlock_detection")]
lockdep: None,
}
}
}
impl<'a, T: ?Sized> Drop for SharedReadLock<'a, T> {
fn drop(&mut self) {
#[cfg(feature = "deadlock_detection")]
if let Some(token) = self.lockdep.take() {
crate::lockdep::release_held(token);
}
if let SharedReadLockInner::Sync(lock) = &self.inner {
let metadata = lock.metadata();
if let Some(poison) = &metadata.poison {
if std::thread::panicking() {
poison.store(true, std::sync::atomic::Ordering::Release);
}
}
}
if let SharedReadLockInner::SyncBox(lock) = &self.inner {
let metadata = lock.metadata();
if let Some(poison) = &metadata.poison {
if std::thread::panicking() {
poison.store(true, std::sync::atomic::Ordering::Release);
}
}
}
}
}
impl<'a, T: ?Sized> From<SynchronizerReadLock<'a, LockMetadata, T>> for SharedReadLock<'a, T> {
fn from(value: SynchronizerReadLock<'a, LockMetadata, T>) -> Self {
#[cfg(feature = "deadlock_detection")]
let lockdep = crate::lockdep::read_guard_token(&value);
SharedReadLock {
inner: SharedReadLockInner::Sync(value),
#[cfg(feature = "deadlock_detection")]
lockdep,
}
}
}
impl<'a, T: ?Sized> From<SynchronizerReadLock<'a, LockMetadata, Box<T>>> for SharedReadLock<'a, T> {
fn from(value: SynchronizerReadLock<'a, LockMetadata, Box<T>>) -> Self {
#[cfg(feature = "deadlock_detection")]
let lockdep = crate::lockdep::read_guard_token(&value);
SharedReadLock {
inner: SharedReadLockInner::SyncBox(value),
#[cfg(feature = "deadlock_detection")]
lockdep,
}
}
}
pub struct SharedReadLockOwned<T: ?Sized + 'static> {
pub(crate) inner: SharedReadLock<'static, T>,
#[allow(unused)]
pub(crate) container: SharedImpl<T>,
}
impl<T: ?Sized + 'static> SharedReadLockOwned<T> {
#[cfg(feature = "async_experimental")]
#[allow(clippy::needless_lifetimes)]
pub(crate) unsafe fn unsafe_reattach<'a>(
self,
_to: &'a SharedImpl<T>,
) -> SharedReadLock<'a, T> {
std::mem::transmute(self.inner)
}
}
pub struct SharedWriteLockOwned<T: ?Sized + 'static> {
pub(crate) inner: SharedWriteLock<'static, T>,
#[allow(unused)]
pub(crate) container: SharedImpl<T>,
}
impl<T: ?Sized + 'static> SharedWriteLockOwned<T> {
#[cfg(feature = "async_experimental")]
#[allow(clippy::needless_lifetimes)]
pub(crate) unsafe fn unsafe_reattach<'a>(
self,
_to: &'a SharedImpl<T>,
) -> SharedWriteLock<'a, T> {
std::mem::transmute(self.inner)
}
}
impl<T: ?Sized + 'static> std::ops::Deref for SharedReadLockOwned<T> {
type Target = <SharedReadLock<'static, T> as std::ops::Deref>::Target;
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl<T: ?Sized + 'static> std::ops::Deref for SharedWriteLockOwned<T> {
type Target = <SharedWriteLock<'static, T> as std::ops::Deref>::Target;
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl<T: ?Sized + 'static> std::ops::DerefMut for SharedWriteLockOwned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.deref_mut()
}
}
pub enum SharedWriteLockInner<'a, T: ?Sized> {
Sync(SynchronizerWriteLock<'a, LockMetadata, T>),
SyncBox(SynchronizerWriteLock<'a, LockMetadata, Box<T>>),
Projection(Box<dyn std::ops::DerefMut<Target = T> + 'a>),
}
#[must_use = "if unused the lock will immediately unlock"]
pub struct SharedWriteLock<'a, T: ?Sized> {
pub(crate) inner: SharedWriteLockInner<'a, T>,
#[cfg(feature = "deadlock_detection")]
pub(crate) lockdep: Option<crate::lockdep::HeldToken>,
}
impl<'a, T: ?Sized> SharedWriteLock<'a, T> {
pub(crate) fn from_projection(inner: Box<dyn std::ops::DerefMut<Target = T> + 'a>) -> Self {
SharedWriteLock {
inner: SharedWriteLockInner::Projection(inner),
#[cfg(feature = "deadlock_detection")]
lockdep: None,
}
}
}
impl<'a, T: ?Sized> From<SynchronizerWriteLock<'a, LockMetadata, T>> for SharedWriteLock<'a, T> {
fn from(value: SynchronizerWriteLock<'a, LockMetadata, T>) -> Self {
#[cfg(feature = "deadlock_detection")]
let lockdep = crate::lockdep::write_guard_token(&value);
SharedWriteLock {
inner: SharedWriteLockInner::Sync(value),
#[cfg(feature = "deadlock_detection")]
lockdep,
}
}
}
impl<'a, T: ?Sized> From<SynchronizerWriteLock<'a, LockMetadata, Box<T>>>
for SharedWriteLock<'a, T>
{
fn from(value: SynchronizerWriteLock<'a, LockMetadata, Box<T>>) -> Self {
#[cfg(feature = "deadlock_detection")]
let lockdep = crate::lockdep::write_guard_token(&value);
SharedWriteLock {
inner: SharedWriteLockInner::SyncBox(value),
#[cfg(feature = "deadlock_detection")]
lockdep,
}
}
}
impl<'a, T: ?Sized> std::ops::Deref for SharedReadLock<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
use SharedReadLockInner::*;
match &self.inner {
Sync(x) => x,
SyncBox(x) => x,
Projection(x) => x,
}
}
}
impl<'a, T: ?Sized> std::ops::Deref for SharedWriteLock<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
use SharedWriteLockInner::*;
match &self.inner {
Sync(x) => x,
SyncBox(x) => x,
Projection(x) => x,
}
}
}
impl<'a, T: ?Sized> std::ops::DerefMut for SharedWriteLock<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
use SharedWriteLockInner::*;
match &mut self.inner {
Sync(x) => &mut *x,
SyncBox(x) => &mut *x,
Projection(x) => &mut *x,
}
}
}
impl<'a, T: ?Sized> Drop for SharedWriteLock<'a, T> {
fn drop(&mut self) {
#[cfg(feature = "deadlock_detection")]
if let Some(token) = self.lockdep.take() {
crate::lockdep::release_held(token);
}
if let SharedWriteLockInner::Sync(lock) = &self.inner {
let metadata = lock.metadata();
if let Some(poison) = &metadata.poison {
if std::thread::panicking() {
poison.store(true, std::sync::atomic::Ordering::Release);
}
}
}
if let SharedWriteLockInner::SyncBox(lock) = &self.inner {
let metadata = lock.metadata();
if let Some(poison) = &metadata.poison {
if std::thread::panicking() {
poison.store(true, std::sync::atomic::Ordering::Release);
}
}
}
}
}
macro_rules! implement_lock_delegates {
($for:ty) => {
impl<'a, T: ?Sized> std::fmt::Debug for $for
where
T: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(**self).fmt(f)
}
}
impl<'a, T: ?Sized> std::fmt::Display for $for
where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(**self).fmt(f)
}
}
impl<'a, T: ?Sized> std::error::Error for $for
where
T: std::error::Error,
{
#[allow(deprecated)]
fn cause(&self) -> Option<&dyn std::error::Error> {
(**self).cause()
}
#[allow(deprecated)]
fn description(&self) -> &str {
(**self).description()
}
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
(**self).source()
}
}
impl<'a, T: ?Sized> std::borrow::Borrow<T> for $for {
fn borrow(&self) -> &T {
&**self
}
}
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for $for
where
T: AsRef<U>,
{
fn as_ref(&self) -> &U {
(**self).as_ref()
}
}
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for $for
where
T: AsMut<U>,
Self: std::ops::DerefMut<Target = T>,
{
fn as_mut(&mut self) -> &mut U {
(**self).as_mut()
}
}
impl<'a, T: ?Sized, Rhs: ?Sized> PartialEq<Rhs> for $for
where
T: PartialEq<Rhs>,
{
fn eq(&self, other: &Rhs) -> bool {
(**self).eq(other)
}
}
impl<'a, T: ?Sized, Rhs: ?Sized> PartialOrd<Rhs> for $for
where
T: PartialOrd<Rhs>,
{
fn partial_cmp(&self, other: &Rhs) -> Option<std::cmp::Ordering> {
(**self).partial_cmp(other)
}
}
impl<'a, T: ?Sized> Unpin for $for {}
};
}
implement_lock_delegates!(SharedReadLock<'a, T>);
implement_lock_delegates!(SharedReadLockOwned<T>);
implement_lock_delegates!(SharedWriteLock<'a, T>);
implement_lock_delegates!(SharedWriteLockOwned<T>);
#[cfg(doctest)]
mod send_test {}
#[cfg(test)]
mod test {
use super::*;
#[allow(unused)]
#[allow(unconditional_recursion)]
fn ensure_locks_send<T: Send>() {
ensure_locks_send::<SharedReadLock<'static, ()>>();
ensure_locks_send::<SharedWriteLock<'static, ()>>();
}
#[allow(unused)]
fn ensure_locks_coerce_deref(read: SharedReadLock<String>) {
fn takes_as_ref(_: &String) {}
fn takes_as_ref_str(_: &impl AsRef<str>) {}
takes_as_ref(&read);
takes_as_ref_str(&read);
assert!(read == *"123");
}
}