#![warn(
clippy::cargo,
clippy::all,
clippy::perf,
clippy::style,
clippy::complexity,
clippy::suspicious,
clippy::correctness,
missing_docs,
missing_copy_implementations,
missing_debug_implementations,
clippy::absolute_paths
)]
#![deny(
unsafe_op_in_unsafe_fn,
clippy::missing_safety_doc,
clippy::undocumented_unsafe_blocks
)]
use std::{
cell::UnsafeCell,
collections::VecDeque,
hint::assert_unchecked,
marker::PhantomData,
mem::MaybeUninit,
ops::Deref,
sync::{
atomic::{fence, AtomicU8, Ordering},
Arc,
},
};
mod inner;
use inner::{Ptr, ReadState, Shared};
pub trait Absorb<O> {
fn absorb(&mut self, operation: O);
}
#[derive(Debug)]
pub struct ReadGuard<'a, T> {
data: &'a T,
state: &'a AtomicU8,
reader: PhantomData<&'a mut Reader<T>>,
}
impl<'a, T> Deref for ReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.data
}
}
impl<T, E> AsRef<E> for ReadGuard<'_, T>
where
E: ?Sized,
T: AsRef<E>,
{
fn as_ref(&self) -> &E {
self.deref().as_ref()
}
}
impl<T> Drop for ReadGuard<'_, T> {
fn drop(&mut self) {
self.state.fetch_and(0b100, Ordering::Release);
}
}
#[derive(Debug)]
pub struct Reader<T> {
inner: Arc<Shared<T>>,
}
impl<T> Reader<T> {
pub fn lock(&mut self) -> ReadGuard<'_, T> {
let update_result =
self.inner
.state
.fetch_update(Ordering::Relaxed, Ordering::Acquire, |value| {
unsafe {
assert_unchecked(value & 0b011 == 0);
}
match value.into() {
Ptr::Value1 => Some(0b001),
Ptr::Value2 => Some(0b110),
}
});
let ptr = unsafe { update_result.unwrap_unchecked().into() };
let data = unsafe { self.inner.get_value(ptr).get().as_ref().unwrap_unchecked() };
ReadGuard {
data,
state: &self.inner.state,
reader: PhantomData,
}
}
}
#[derive(Debug)]
pub struct WriteGuard<'a, T, O> {
writer: &'a mut Writer<T, O>,
}
impl<T, O> WriteGuard<'_, T, O> {
pub fn swap(self) {}
#[must_use]
pub fn read(&self) -> &T {
self.writer.read()
}
fn get_data_mut(&mut self) -> &mut T {
unsafe { self.get_data_ptr().as_mut().unwrap() }
}
fn get_data_ptr(&self) -> *mut T {
self.writer.shared.get_value(self.writer.write_ptr).get()
}
}
impl<'a, T: Absorb<O>, O> WriteGuard<'a, T, O> {
unsafe fn new(writer: &'a mut Writer<T, O>) -> Self {
let mut guard = Self { writer };
while let Some(operation) = guard.writer.op_buffer.pop_front() {
guard.get_data_mut().absorb(operation);
}
guard
}
}
impl<T: Absorb<O>, O: Clone> WriteGuard<'_, T, O> {
pub fn apply_op(&mut self, operation: O) {
if let Some(inner) = Arc::get_mut(&mut self.writer.shared) {
inner.value_1.get_mut().absorb(operation.clone());
inner.value_2.get_mut().absorb(operation);
} else {
self.writer.op_buffer.push_back(operation.clone());
self.get_data_mut().absorb(operation);
}
}
}
impl<T, O> Drop for WriteGuard<'_, T, O> {
fn drop(&mut self) {
self.writer.swap();
}
}
#[derive(Debug)]
pub struct Writer<T, O> {
shared: Arc<Shared<T>>,
write_ptr: Ptr,
op_buffer: VecDeque<O>,
}
impl<T, O> Writer<T, O> {
fn swap(&mut self) {
if self.op_buffer.is_empty() {
return;
}
match self.write_ptr {
Ptr::Value1 => self.shared.state.fetch_and(0b011, Ordering::Release),
Ptr::Value2 => self.shared.state.fetch_or(0b100, Ordering::Release),
};
self.write_ptr.switch();
}
pub fn build_reader(&mut self) -> Option<Reader<T>> {
if Arc::get_mut(&mut self.shared).is_some() {
Some(Reader {
inner: self.shared.clone(),
})
} else {
None
}
}
#[must_use]
pub fn read(&self) -> &T {
unsafe {
self.shared
.get_value(self.write_ptr)
.get()
.as_ref()
.unwrap_unchecked()
}
}
}
impl<T: Absorb<O>, O> Writer<T, O> {
pub fn lock(&mut self) -> WriteGuard<'_, T, O> {
let backoff = crossbeam_utils::Backoff::new();
loop {
let state = self.shared.state.load(Ordering::Relaxed);
if ReadState::from(state).can_write(self.write_ptr) {
fence(Ordering::Acquire);
break;
}
backoff.snooze();
}
unsafe { WriteGuard::new(self) }
}
pub fn try_lock(&mut self) -> Option<WriteGuard<'_, T, O>> {
let state = self.shared.state.load(Ordering::Acquire);
if ReadState::from(state).can_write(self.write_ptr) {
unsafe { Some(WriteGuard::new(self)) }
} else {
None
}
}
}
impl<T: Clone, O> Writer<T, O> {
pub fn new(value: T) -> Self {
let mut shared: Arc<MaybeUninit<Shared<T>>> = Arc::new_uninit();
let shared_ptr = unsafe { Arc::get_mut(&mut shared).unwrap_unchecked() }.as_mut_ptr();
let state_ptr: *mut AtomicU8 = unsafe { &raw mut (*shared_ptr).state };
unsafe { state_ptr.write(AtomicU8::new(0b000)) };
let value_1_ptr: *mut UnsafeCell<T> = unsafe { &raw mut (*shared_ptr).value_1 };
unsafe { value_1_ptr.cast::<T>().write(value.clone()) };
let value_2_ptr: *mut UnsafeCell<T> = unsafe { &raw mut (*shared_ptr).value_2 };
unsafe { value_2_ptr.cast::<T>().write(value) };
let shared: Arc<Shared<T>> = unsafe { shared.assume_init() };
Writer {
shared,
write_ptr: Ptr::Value2,
op_buffer: VecDeque::new(),
}
}
}
impl<T: Default, O> Default for Writer<T, O> {
fn default() -> Self {
let mut shared: Arc<MaybeUninit<Shared<T>>> = Arc::new_uninit();
let shared_ptr = unsafe { Arc::get_mut(&mut shared).unwrap_unchecked() }.as_mut_ptr();
let state_ptr: *mut AtomicU8 = unsafe { &raw mut (*shared_ptr).state };
unsafe { state_ptr.write(AtomicU8::new(0b000)) };
let value_1_ptr: *mut UnsafeCell<T> = unsafe { &raw mut (*shared_ptr).value_1 };
unsafe { value_1_ptr.cast::<T>().write(T::default()) };
let value_2_ptr: *mut UnsafeCell<T> = unsafe { &raw mut (*shared_ptr).value_2 };
unsafe { value_2_ptr.cast::<T>().write(T::default()) };
let shared: Arc<Shared<T>> = unsafe { shared.assume_init() };
Writer {
shared,
write_ptr: Ptr::Value2,
op_buffer: VecDeque::new(),
}
}
}