ratio_clone/
mrc.rs

1//! # Mutable 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::cell::{Cell, RefCell};
17use std::ops::{Deref, DerefMut};
18use std::rc::Rc;
19
20use crate::{BorrowDeref, BorrowDerefMut, InnerEq};
21
22thread_local! {
23    /// Thread local counter for single threaded types.
24    static NONCE: Cell<usize> =  Cell::new(0);
25}
26/// Fetch the next number used once for single threaded usage.
27fn next_nonce() -> usize {
28    NONCE
29        .try_with(|cell| {
30            let val = cell.get().wrapping_add(1);
31            cell.set(val);
32            val
33        })
34        .expect("Nonce thread local counter initialization should succeed.")
35}
36
37/// Atomic counted wrapper that updates a nonce counter on every mutable access of the inner content
38/// in an inner mutable container such as an RwLock or Mutex. It's PartialEq behavior is reduced to
39/// comparing the memory location and counter index. For the potentially expensive true inner
40/// equality comparison, look for the implementation of `inner_eq`.
41#[derive(Debug)]
42pub struct Mrc<T> {
43    inner: Rc<T>,
44    nonce: Cell<usize>,
45}
46impl<T: Default> Default for Mrc<T> {
47    fn default() -> Self {
48        Self::from(T::default())
49    }
50}
51
52impl<T> From<T> for Mrc<T> {
53    fn from(value: T) -> Self {
54        Self {
55            inner: Rc::new(value),
56            nonce: Cell::new(next_nonce()),
57        }
58    }
59}
60
61impl<T> Clone for Mrc<T> {
62    fn clone(&self) -> Self {
63        Self {
64            inner: self.inner.clone(),
65            nonce: Cell::new(self.nonce.get()),
66        }
67    }
68}
69
70impl<T> PartialEq for Mrc<T> {
71    fn eq(&self, other: &Self) -> bool {
72        Rc::ptr_eq(&self.inner, &other.inner) && self.nonce.get() == other.nonce.get()
73    }
74}
75
76/// Generic Marc implementation.
77impl<T> Mrc<T> {
78    /// Create a new Mrc with a RefCell governing interior mutability (for types that are Clone).
79    pub fn new_refcell(value: T) -> Mrc<RefCell<T>> {
80        Mrc::<RefCell<T>>::from(RefCell::new(value))
81    }
82}
83
84/// RefCell backed Mrc implementation.
85impl<T> Mrc<RefCell<T>> {
86    /// Create a new Marc instance with an RwLock governing interior mutability.
87    pub fn new(value: T) -> Self {
88        Self::from(RefCell::new(value))
89    }
90}
91impl<T> BorrowDerefMut<T> for Mrc<RefCell<T>> {
92    fn borrow_mut(&self) -> impl DerefMut<Target = T> + '_ {
93        self.nonce.set(next_nonce());
94        self.inner.borrow_mut()
95    }
96}
97impl<T> BorrowDeref<T> for Mrc<RefCell<T>> {
98    fn borrow(&self) -> impl Deref<Target = T> + '_ {
99        self.inner.borrow()
100    }
101}
102impl<T: PartialOrd> PartialOrd for Mrc<RefCell<T>> {
103    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
104        self.borrow().deref().partial_cmp(other.borrow().deref())
105    }
106}
107impl<T: PartialEq> InnerEq<T> for Mrc<RefCell<T>> {
108    fn inner_eq(&self, other: &Self) -> bool {
109        self.borrow().deref() == other.borrow().deref()
110    }
111}
112#[cfg(feature = "serde")]
113impl<T: serde::Serialize> serde::Serialize for Mrc<RefCell<T>> {
114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115    where
116        S: serde::Serializer,
117    {
118        T::serialize(self.borrow().deref(), serializer)
119    }
120}
121#[cfg(feature = "serde")]
122impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Mrc<RefCell<T>> {
123    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
124    where
125        D: serde::Deserializer<'de>,
126    {
127        T::deserialize(deserializer).map(Self::new)
128    }
129}