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, InnerEq};
21
22/// Atomic/multi-threaded counter shared by atomic types.
23static NONCE: AtomicUsize = AtomicUsize::new(0);
24/// Fetch the next number used once for atomic/multi-threaded usage.
25fn next_nonce() -> usize {
26    NONCE.fetch_add(1, Ordering::Relaxed)
27}
28
29/// Atomic counted wrapper that updates a nonce counter on every mutable access of the inner content
30/// in an inner mutable container such as an RwLock or Mutex. It's PartialEq behavior is reduced to
31/// comparing the memory location and counter index. For the potentially expensive true inner
32/// equality comparison, look for the implementation of `inner_eq`.
33#[derive(Debug)]
34pub struct Marc<T> {
35    inner: Arc<T>,
36    nonce: AtomicUsize,
37}
38impl<T: Default> Default for Marc<T> {
39    fn default() -> Self {
40        Self::from(T::default())
41    }
42}
43
44impl<T> From<T> for Marc<T> {
45    fn from(value: T) -> Self {
46        Self {
47            inner: Arc::new(value),
48            nonce: next_nonce().into(),
49        }
50    }
51}
52
53impl<T> Clone for Marc<T> {
54    fn clone(&self) -> Self {
55        Self {
56            inner: self.inner.clone(),
57            nonce: AtomicUsize::new(self.nonce.load(Ordering::Relaxed)),
58        }
59    }
60}
61
62impl<T> PartialEq for Marc<T> {
63    fn eq(&self, other: &Self) -> bool {
64        Arc::ptr_eq(&self.inner, &other.inner)
65            && self.nonce.load(Ordering::Relaxed) == other.nonce.load(Ordering::Relaxed)
66    }
67}
68
69/// Generic Marc implementation.
70impl<T> Marc<T> {
71    /// Create a new Marc with an RwLock governing interior mutability.
72    pub fn new_rw(value: T) -> Marc<RwLock<T>> {
73        Marc::<RwLock<T>>::from(RwLock::new(value))
74    }
75
76    /// Create a new Marc with a Mutex governing interior mutability.
77    pub fn new_mutex(value: T) -> Marc<Mutex<T>> {
78        Marc::<Mutex<T>>::from(Mutex::new(value))
79    }
80}
81
82/// RwLock backed Marc implementation.
83impl<T> Marc<RwLock<T>> {
84    /// Create a new Marc instance with an RwLock governing interior mutability.
85    pub fn new(value: T) -> Self {
86        Self::from(RwLock::new(value))
87    }
88}
89impl<T> BorrowDerefMut<T> for Marc<RwLock<T>> {
90    fn borrow_mut(&self) -> impl DerefMut<Target = T> + '_ {
91        self.nonce
92            .store(NONCE.fetch_add(1, Ordering::Relaxed), Ordering::Relaxed);
93        self.inner.write().expect("poison free RwLock")
94    }
95}
96impl<T> BorrowDeref<T> for Marc<RwLock<T>> {
97    fn borrow(&self) -> impl Deref<Target = T> + '_ {
98        self.inner.read().expect("poison free RwLock")
99    }
100}
101impl<T: PartialOrd> PartialOrd for Marc<RwLock<T>> {
102    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
103        self.borrow().deref().partial_cmp(other.borrow().deref())
104    }
105}
106impl<T: PartialEq> InnerEq<T> for Marc<RwLock<T>> {
107    fn inner_eq(&self, other: &Self) -> bool {
108        self.borrow().deref() == other.borrow().deref()
109    }
110}
111#[cfg(feature = "serde")]
112impl<T: serde::Serialize> serde::Serialize for Marc<RwLock<T>> {
113    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
114    where
115        S: serde::Serializer,
116    {
117        T::serialize(self.borrow().deref(), serializer)
118    }
119}
120#[cfg(feature = "serde")]
121impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Marc<RwLock<T>> {
122    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
123    where
124        D: serde::Deserializer<'de>,
125    {
126        T::deserialize(deserializer).map(Self::new)
127    }
128}
129
130/// Mutex backed Marc implementation.
131impl<T> Marc<Mutex<T>> {
132    /// Create a new Marc instance with a Mutex governing interior mutability.
133    pub fn new(value: T) -> Self {
134        Self::from(Mutex::new(value))
135    }
136}
137impl<T> BorrowDerefMut<T> for Marc<Mutex<T>> {
138    fn borrow_mut(&self) -> impl DerefMut<Target = T> + '_ {
139        self.nonce.store(next_nonce(), Ordering::Relaxed);
140        self.inner.lock().expect("poison free Mutex")
141    }
142}
143impl<T> BorrowDeref<T> for Marc<Mutex<T>> {
144    fn borrow(&self) -> impl Deref<Target = T> + '_ {
145        self.inner.lock().expect("poison free Mutex")
146    }
147}
148impl<T: PartialOrd> PartialOrd for Marc<Mutex<T>> {
149    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
150        self.borrow().deref().partial_cmp(other.borrow().deref())
151    }
152}
153#[cfg(feature = "serde")]
154impl<T: serde::Serialize> serde::Serialize for Marc<Mutex<T>> {
155    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156    where
157        S: serde::Serializer,
158    {
159        T::serialize(self.borrow().deref(), serializer)
160    }
161}
162#[cfg(feature = "serde")]
163impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Marc<Mutex<T>> {
164    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165    where
166        D: serde::Deserializer<'de>,
167    {
168        T::deserialize(deserializer).map(Self::new)
169    }
170}