#![no_std]
extern crate alloc;
use core::{marker::PhantomData, ops::Deref, ptr::NonNull};
use alloc::collections::vec_deque::VecDeque;
mod shared;
use shared::{Ptr, Shared};
pub trait Absorb<O> {
fn absorb(&mut self, operation: O);
}
#[derive(Debug)]
pub struct Reader<T> {
shared: NonNull<Shared<T>>,
locked: bool,
_own: PhantomData<Shared<T>>,
}
impl<T> Reader<T> {
fn shared_ref(&self) -> &Shared<T> {
unsafe { self.shared.as_ref() }
}
pub fn lock(&mut self) -> ReadGuard<'_, T> {
if self.locked {
self.locked = false;
panic!("ReadGuard was forgotten");
}
self.locked = true;
let value = unsafe { &*self.shared_ref().lock_read().get() };
ReadGuard {
value,
reader: self,
}
}
}
unsafe impl<T: Send> Send for Reader<T> {}
impl<T> Drop for Reader<T> {
fn drop(&mut self) {
unsafe { Shared::drop(self.shared) };
assert!(!self.locked, "ReadGuard was forgotten");
}
}
#[derive(Debug)]
pub struct ReadGuard<'a, T> {
reader: &'a mut Reader<T>,
value: &'a T,
}
impl<T> Deref for ReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
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.reader.shared_ref().release_read_lock();
self.reader.locked = false;
}
}
#[derive(Debug)]
pub struct Writer<T, O> {
shared: NonNull<Shared<T>>,
write_ptr: Ptr,
op_buffer: VecDeque<O>,
locked: bool,
_own: PhantomData<Shared<T>>,
}
impl<T, O> Writer<T, O> {
fn shared_ref(&self) -> &Shared<T> {
unsafe { self.shared.as_ref() }
}
fn shared_mut(&mut self) -> Option<&mut Shared<T>> {
self.shared_ref()
.is_unique()
.then(|| unsafe { &mut *self.shared.as_ptr() })
}
fn swap(&mut self) {
if self.op_buffer.is_empty() {
return;
}
self.shared_ref().set_read_ptr(self.write_ptr);
self.write_ptr.switch();
}
pub fn build_reader(&mut self) -> Option<Reader<T>> {
let shared_ref = self.shared_ref();
unsafe {
shared_ref.is_unique().then(|| {
shared_ref.set_shared();
Reader {
shared: self.shared,
_own: PhantomData,
locked: false,
}
})
}
}
}
impl<T: Absorb<O>, O> Writer<T, O> {
pub fn try_lock(&mut self) -> Option<WriteGuard<'_, T, O>> {
if self.locked {
self.locked = false;
panic!("WriteGuard was forgotten");
}
self.shared_ref()
.lock_write(self.write_ptr)
.ok()
.map(|()| {
self.locked = true;
let mut guard = WriteGuard { writer: self };
while let Some(operation) = guard.writer.op_buffer.pop_front() {
guard.get_data_mut().absorb(operation);
}
guard
})
}
}
impl<T: Clone, O> Writer<T, O> {
pub fn new(value: T) -> Self {
let (shared, write_ptr) = Shared::new(value, |value_1| value_1.clone());
Self {
shared,
write_ptr,
op_buffer: VecDeque::new(),
_own: PhantomData,
locked: false,
}
}
}
impl<T: Default, O> Default for Writer<T, O> {
fn default() -> Self {
let (shared, write_ptr) = Shared::new(T::default(), |_| T::default());
Self {
shared,
write_ptr,
op_buffer: VecDeque::new(),
_own: PhantomData,
locked: false,
}
}
}
impl<T: Sync, O> Writer<T, O> {
pub fn read(&self) -> &T {
unsafe { self.shared_ref().get_value_ref(self.write_ptr) }
}
}
unsafe impl<T: Send, O: Send> Send for Writer<T, O> {}
unsafe impl<T: Sync, O> Sync for Writer<T, O> {}
impl<T, O> Drop for Writer<T, O> {
fn drop(&mut self) {
unsafe { Shared::drop(self.shared) };
assert!(!self.locked, "WriteGuard was forgotten");
}
}
#[derive(Debug)]
pub struct WriteGuard<'a, T, O> {
writer: &'a mut Writer<T, O>,
}
impl<T, O> WriteGuard<'_, T, O> {
pub fn swap(self) {}
pub fn read(&self) -> &T {
unsafe {
self.writer
.shared_ref()
.get_value_ref(self.writer.write_ptr)
}
}
fn get_data_mut(&mut self) -> &mut T {
unsafe {
&mut *self
.writer
.shared_ref()
.get_value(self.writer.write_ptr)
.get()
}
}
}
impl<T: Absorb<O>, O: Clone> WriteGuard<'_, T, O> {
pub fn apply_op(&mut self, operation: O) {
if let Some(shared) = self.writer.shared_mut() {
shared.value_1.get_mut().absorb(operation.clone());
shared.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();
self.writer.locked = false;
}
}
#[cfg(test)]
mod internal_test {
use core::cell::Cell;
use crate::{Absorb, Writer};
#[derive(Clone, Copy, Debug)]
pub struct CounterAddOp(i32);
impl Absorb<CounterAddOp> for i32 {
fn absorb(&mut self, operation: CounterAddOp) {
*self += operation.0;
}
}
impl Absorb<CounterAddOp> for Cell<i32> {
fn absorb(&mut self, operation: CounterAddOp) {
self.set(self.get() + operation.0);
}
}
#[test]
fn drop_reader() {
let mut writer: Writer<i32, CounterAddOp> = Writer::default();
let reader = writer.build_reader().unwrap();
assert!(!writer.shared_ref().is_unique());
drop(reader);
assert!(writer.shared_ref().is_unique());
}
#[test]
fn drop_writer() {
let mut writer: Writer<i32, CounterAddOp> = Writer::default();
let reader = writer.build_reader().unwrap();
assert!(!reader.shared_ref().is_unique());
drop(writer);
assert!(reader.shared_ref().is_unique());
}
}