use arc_swap::ArcSwap;
use core::ops::{Deref, DerefMut, Drop};
use std::fmt::{Display, Formatter, Result};
use std::sync::Arc;
#[derive(Debug)]
pub struct CloneReplace<T> {
data: Arc<ArcSwap<T>>,
}
impl<T> Clone for CloneReplace<T> {
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
}
}
}
impl<T: Default> Default for CloneReplace<T> {
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T> CloneReplace<T> {
pub fn new(data: T) -> Self {
Self {
data: Arc::new(ArcSwap::new(Arc::new(data))),
}
}
pub fn access(&self) -> Arc<T> {
self.data.load_full()
}
fn set_value(&self, value: T) {
self.data.swap(Arc::new(value));
}
}
impl<T: Clone> CloneReplace<T> {
pub fn mutate(&self) -> MutateGuard<T> {
let inner = &*self.data.load_full();
MutateGuard {
origin: self.clone(),
data: Some(inner.clone()),
}
}
}
pub struct MutateGuard<T> {
origin: CloneReplace<T>,
data: Option<T>,
}
impl<T> MutateGuard<T> {
pub fn discard(mut self) {
self.data = None;
}
}
impl<T> Deref for MutateGuard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.data.as_ref().unwrap()
}
}
impl<T> DerefMut for MutateGuard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data.as_mut().unwrap()
}
}
impl<T: Display> Display for MutateGuard<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
self.data.as_ref().unwrap().fmt(f)
}
}
impl<T> Drop for MutateGuard<T> {
fn drop(&mut self) {
if let Some(data) = self.data.take() {
self.origin.set_value(data);
}
}
}
#[cfg(test)]
mod tests {
use super::CloneReplace;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug)]
struct Foo {
pub a: i32,
}
impl Display for Foo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.a.fmt(f)
}
}
#[test]
fn test_basic() {
let cr = CloneReplace::new(Foo { a: 0 });
let v1 = cr.access();
assert_eq!(v1.a, 0);
{
let mut m = cr.mutate();
assert_eq!(m.a, 0);
m.a = 2;
assert_eq!(m.a, 2);
let v2 = cr.access();
assert_eq!(v1.a, 0);
assert_eq!(v2.a, 0);
}
let v3 = cr.access();
assert_eq!(v3.a, 2);
assert_eq!(v1.a, 0);
}
#[test]
fn test_discard() {
let cr = CloneReplace::new(Foo { a: 5 });
let v1 = cr.access();
assert_eq!(v1.a, 5);
{
let mut m = cr.mutate();
assert_eq!(m.a, 5);
m.a = 1;
assert_eq!(m.a, 1);
let v2 = cr.access();
assert_eq!(v1.a, 5);
assert_eq!(v2.a, 5);
m.discard();
}
let v3 = cr.access();
assert_eq!(v3.a, 5);
assert_eq!(v1.a, 5);
}
#[test]
fn test_display() {
let cr = CloneReplace::new(Foo { a: 3 });
let v1 = cr.access();
assert_eq!(v1.to_string(), "3");
{
let mut m = cr.mutate();
assert_eq!(m.to_string(), "3");
m.a = 2;
assert_eq!(m.to_string(), "2");
let v2 = cr.access();
assert_eq!(v1.to_string(), "3");
assert_eq!(v2.to_string(), "3");
}
let v3 = cr.access();
assert_eq!(v3.to_string(), "2");
assert_eq!(v1.to_string(), "3");
}
#[test]
fn test_multiple_writers() {
let cr = CloneReplace::new(Foo { a: 4 });
let v1 = cr.access();
assert_eq!(v1.a, 4);
{
let mut m1 = cr.mutate();
let mut m2 = cr.mutate();
assert_eq!(m1.a, 4);
m1.a = 1;
assert_eq!(m1.a, 1);
let v2 = cr.access();
assert_eq!(v1.a, 4);
assert_eq!(v2.a, 4);
assert_eq!(m2.a, 4);
m2.a = 5;
assert_eq!(m2.a, 5);
let v3 = cr.access();
assert_eq!(v1.a, 4);
assert_eq!(v2.a, 4);
assert_eq!(v3.a, 4);
assert_eq!(m1.a, 1);
}
let v4 = cr.access();
assert_eq!(v4.a, 1);
assert_eq!(v1.a, 4);
}
}