use super::{
compare_exchange, DetachedArc, ReadArc, RelaxStrategy, RwArcInner, Spin, UpgradableArc, READER,
UPGRADED, WRITER,
};
use crate::externs::{
fmt, mem,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
sync::{atomic::Ordering, Arc},
};
pub struct WriteArc<T: ?Sized, R = Spin> {
pub(super) inner: Arc<RwArcInner<T, R>>,
}
impl<T, R: RelaxStrategy> WriteArc<T, R> {
pub fn from_detached(mut self, detached: DetachedArc<T, R>) -> Self {
let inner = detached.inner;
let mut self_data = self.inner.data.get();
let mut detach_data = inner.data.get();
unsafe {
mem::swap(&mut self_data, &mut detach_data);
}
self
}
}
unsafe impl<T: ?Sized + Send + Sync, R> Send for WriteArc<T, R> {}
unsafe impl<T: ?Sized + Send + Sync, R> Sync for WriteArc<T, R> {}
impl<T: ?Sized + fmt::Debug, R> fmt::Debug for WriteArc<T, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized + fmt::Display, R> fmt::Display for WriteArc<T, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<T: ?Sized, R> Drop for WriteArc<T, R> {
fn drop(&mut self) {
debug_assert_eq!(self.inner.lock.load(Ordering::Relaxed) & WRITER, WRITER);
self.inner
.lock
.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
}
}
impl<T: ?Sized, R> Deref for WriteArc<T, R> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.inner.data.get() }
}
}
impl<T: ?Sized, R> DerefMut for WriteArc<T, R> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.inner.data.get() }
}
}
impl<'rwlock, T: ?Sized, R> WriteArc<T, R> {
pub fn downgrade(self) -> ReadArc<T, R> {
self.inner.acquire_reader();
let inner = self.inner.clone();
mem::drop(self);
ReadArc { inner }
}
pub fn downgrade_to_upgradeable(self) -> UpgradableArc<T, R> {
debug_assert_eq!(
self.inner.lock.load(Ordering::Acquire) & (WRITER | UPGRADED),
WRITER
);
self.inner.lock.store(UPGRADED, Ordering::Release);
let inner = self.inner.clone();
mem::forget(self);
UpgradableArc { inner }
}
pub fn leak(this: Self) -> &'rwlock mut T {
let mut this = ManuallyDrop::new(this);
unsafe { &mut *this.inner.data.get() }
}
}