#![cfg_attr(not(test), no_std)]
extern crate alloc;
use alloc::{boxed::Box, sync::Arc};
use atomicbox::AtomicOptionBox;
use core::{
fmt,
hint::spin_loop,
ops::{Deref, DerefMut},
sync::atomic::Ordering,
};
pub struct Wrrm<T> {
inner: AtomicOptionBox<Arc<T>>,
}
impl<T> Wrrm<T> {
pub fn new(value: T) -> Self {
Wrrm {
inner: AtomicOptionBox::new(Some(Box::new(Arc::new(value)))),
}
}
pub fn access(&self) -> Access<'_, T> {
let inner = loop {
if let Some(value) = self.inner.take(Ordering::AcqRel) {
let _updated = self.inner.swap(Some(value.clone()), Ordering::AcqRel);
debug_assert!(_updated.is_none());
break *value;
}
spin_loop();
};
Access {
parent: self,
inner,
}
}
pub fn modify_with(&self, modification: impl FnMut(&mut T))
where
T: Clone,
{
Access::modify_with(self.access(), modification)
}
pub fn replace(&self, new_value: T) {
self.inner
.store(Some(Box::new(Arc::new(new_value))), Ordering::AcqRel);
}
}
impl<T: Clone> Clone for Wrrm<T> {
fn clone(&self) -> Self {
Wrrm::new(<T as Clone>::clone(&self.access()))
}
}
impl<T: Default> Default for Wrrm<T> {
fn default() -> Self {
Wrrm::new(Default::default())
}
}
impl<T> From<T> for Wrrm<T> {
fn from(value: T) -> Self {
Wrrm::new(value)
}
}
impl<T> fmt::Debug for Wrrm<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.access(), f)
}
}
pub struct Access<'a, T> {
parent: &'a Wrrm<T>,
inner: Arc<T>,
}
impl<'a, T: Clone> Access<'a, T> {
pub fn modify_with(mut me: Self, mut modification: impl FnMut(&mut T)) {
loop {
let mut modify = Modify::from(me);
modification(&mut *modify);
match Modify::apply(modify) {
Ok(()) => return,
Err(acc) => me = acc,
}
}
}
pub fn replace(me: Self, new_value: T) {
me.parent.replace(new_value);
}
}
impl<'a, T> Deref for Access<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, T> fmt::Debug for Access<'a, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<T as fmt::Debug>::fmt(&*self.inner, f)
}
}
pub struct Modify<'a, T> {
parent: &'a Wrrm<T>,
expected: Arc<T>,
new_value: T,
}
impl<'a, T: Clone> From<Access<'a, T>> for Modify<'a, T> {
fn from(access: Access<'a, T>) -> Self {
Modify {
parent: access.parent,
new_value: <T as Clone>::clone(&*access.inner),
expected: access.inner,
}
}
}
impl<'a, T> Modify<'a, T> {
pub fn apply(me: Self) -> Result<(), Access<'a, T>> {
loop {
if let Some(in_ptr) = me.parent.inner.take(Ordering::AcqRel) {
if Arc::ptr_eq(&*in_ptr, &me.expected) {
let new_value = Box::new(Arc::new(me.new_value));
let _updated = me.parent.inner.swap(Some(new_value), Ordering::AcqRel);
debug_assert!(_updated.is_none());
return Ok(());
} else {
let _updated = me.parent.inner.swap(Some(in_ptr.clone()), Ordering::AcqRel);
debug_assert!(_updated.is_none());
return Err(Access {
parent: me.parent,
inner: *in_ptr,
});
}
}
spin_loop();
}
}
}
impl<'a, T> Deref for Modify<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.new_value
}
}
impl<'a, T> DerefMut for Modify<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.new_value
}
}
impl<'a, T> fmt::Debug for Modify<'a, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<T as fmt::Debug>::fmt(&self.new_value, f)
}
}
#[cfg(test)]
mod tests {
use super::Wrrm;
use std::{
sync::{Arc, Barrier},
thread,
time::Duration,
};
#[test]
fn basic() {
let val = Wrrm::from(5);
let first_access = val.access();
assert_eq!(*first_access, 5);
val.modify_with(|v| *v = 6);
assert_eq!(*val.access(), 6);
assert_eq!(*first_access, 5);
}
#[test]
fn threads() {
let val = Arc::new(Wrrm::from(5));
let barrier = Arc::new(Barrier::new(256));
for _ in 0..256 {
let val = val.clone();
let barrier = barrier.clone();
thread::spawn(move || {
barrier.wait();
let mut seen_value = i32::MAX;
val.modify_with(|v| {
*v += 1;
seen_value = *v;
});
assert!(*val.access() >= seen_value);
});
}
loop {
thread::sleep(Duration::from_millis(200));
if *val.access() == 261 {
break;
}
}
thread::sleep(Duration::from_secs(3));
assert_eq!(*val.access(), 261);
}
}