ratio_clone/
marc.rs

1//! # Mutable atomic reference counted wrapper type
2//!
3//! The Marc features interior mutability using a Mutex or RwLock and a internal AtomicUsize that
4//! counts mutable accesses. This is useful in cases where the interior type is expensive to
5//! clone-on-write as well as expensive to compare (PartialEq). Please use a plain Arc when that is
6//! not the case, as the Marc might be overkill otherwise.
7//!
8//! ## License
9//!
10//! This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy
11//! of the MPL was not distributed with this file, You can obtain one at
12//! <https://mozilla.org/MPL/2.0/>.
13//!
14//! **Code examples both in the docstrings and rendered documentation are free to use.**
15
16use std::ops::{Deref, DerefMut};
17use std::sync::atomic::{AtomicUsize, Ordering};
18use std::sync::{Arc, Mutex, RwLock};
19
20use crate::{BorrowDeref, BorrowDerefMut};
21
22/// Global nonce generational counter.
23static NONCE: AtomicUsize = AtomicUsize::new(0);
24
25/// Atomic counted wrapper that updates a nonce counter on every mutable access of the inner content
26/// in an inner mutable container such as an RwLock or Mutex. It's PartialEq behavior is reduced to
27/// comparing the memory location and counter index. For the potentially expensive true inner
28/// equality comparison, look for the implementation of `inner_eq`.
29#[derive(Debug)]
30pub struct Marc<T> {
31    inner: Arc<T>,
32    nonce: AtomicUsize,
33}
34impl<T: Default> Default for Marc<T> {
35    fn default() -> Self {
36        Self::from(T::default())
37    }
38}
39
40impl<T> From<T> for Marc<T> {
41    fn from(value: T) -> Self {
42        Self {
43            inner: Arc::new(value),
44            nonce: NONCE.fetch_add(1, Ordering::Relaxed).into(),
45        }
46    }
47}
48
49impl<T> Clone for Marc<T> {
50    fn clone(&self) -> Self {
51        Self {
52            inner: self.inner.clone(),
53            nonce: AtomicUsize::new(self.nonce.load(Ordering::Relaxed)),
54        }
55    }
56}
57
58impl<T> PartialEq for Marc<T> {
59    fn eq(&self, other: &Self) -> bool {
60        Arc::ptr_eq(&self.inner, &other.inner)
61            && self.nonce.load(Ordering::Relaxed) == other.nonce.load(Ordering::Relaxed)
62    }
63}
64
65/// Generic Marc implementation.
66impl<T> Marc<T> {
67    /// Create a new RwLock with an RwLock governing interior mutability.
68    pub fn new_rw(value: T) -> Marc<RwLock<T>> {
69        Marc::<RwLock<T>>::from(RwLock::new(value))
70    }
71
72    /// Create a new RwLock with a Mutex governing interior mutability.
73    pub fn new_mutex(value: T) -> Marc<Mutex<T>> {
74        Marc::<Mutex<T>>::from(Mutex::new(value))
75    }
76}
77
78/// RwLock backed Marc implementation.
79impl<T> Marc<RwLock<T>> {
80    /// Create a new Marc instance with an RwLock governing interior mutability.
81    pub fn new(value: T) -> Self {
82        Self::from(RwLock::new(value))
83    }
84}
85impl<T> BorrowDerefMut<T> for Marc<RwLock<T>> {
86    fn borrow_mut(&self) -> impl DerefMut<Target = T> + '_ {
87        self.nonce
88            .store(NONCE.fetch_add(1, Ordering::Relaxed), Ordering::Relaxed);
89        self.inner.write().expect("poison free RwLock")
90    }
91}
92impl<T> BorrowDeref<T> for Marc<RwLock<T>> {
93    fn borrow(&self) -> impl Deref<Target = T> + '_ {
94        self.inner.read().expect("poison free RwLock")
95    }
96}
97impl<T: PartialOrd> PartialOrd for Marc<RwLock<T>> {
98    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
99        self.borrow().deref().partial_cmp(other.borrow().deref())
100    }
101}
102#[cfg(feature = "serde")]
103impl<T: serde::Serialize> serde::Serialize for Marc<RwLock<T>> {
104    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
105    where
106        S: serde::Serializer,
107    {
108        T::serialize(self.borrow().deref(), serializer)
109    }
110}
111#[cfg(feature = "serde")]
112impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Marc<RwLock<T>> {
113    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114    where
115        D: serde::Deserializer<'de>,
116    {
117        T::deserialize(deserializer).map(Self::new)
118    }
119}
120
121/// Mutex backed Marc implementation.
122impl<T> Marc<Mutex<T>> {
123    /// Create a new Marc instance with a Mutex governing interior mutability.
124    pub fn new(value: T) -> Self {
125        Self::from(Mutex::new(value))
126    }
127}
128impl<T> BorrowDerefMut<T> for Marc<Mutex<T>> {
129    fn borrow_mut(&self) -> impl DerefMut<Target = T> + '_ {
130        self.nonce
131            .store(NONCE.fetch_add(1, Ordering::Relaxed), Ordering::Relaxed);
132        self.inner.lock().expect("poison free Mutex")
133    }
134}
135impl<T> BorrowDeref<T> for Marc<Mutex<T>> {
136    fn borrow(&self) -> impl Deref<Target = T> + '_ {
137        self.inner.lock().expect("poison free Mutex")
138    }
139}
140impl<T: PartialOrd> PartialOrd for Marc<Mutex<T>> {
141    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
142        self.borrow().deref().partial_cmp(other.borrow().deref())
143    }
144}
145#[cfg(feature = "serde")]
146impl<T: serde::Serialize> serde::Serialize for Marc<Mutex<T>> {
147    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148    where
149        S: serde::Serializer,
150    {
151        T::serialize(self.borrow().deref(), serializer)
152    }
153}
154#[cfg(feature = "serde")]
155impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Marc<Mutex<T>> {
156    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157    where
158        D: serde::Deserializer<'de>,
159    {
160        T::deserialize(deserializer).map(Self::new)
161    }
162}