clone_replace/
lib.rs

1//!
2//! # clone-replace
3//!
4//! A [CloneReplace] is a synchronisation primitive that provides
5//! owned handles for shared data.
6//!
7//! Example:
8//! ```rust
9//! use clone_replace::CloneReplace;
10//!
11//! let data = CloneReplace::new(1);
12//!
13//! let v1 = data.access();
14//! assert_eq!(*v1, 1);
15//! {
16//!    let mut m = data.mutate();
17//!    *m = 2;
18//!    let v2 = data.access();
19//!    assert_eq!(*v1, 1);
20//!    assert_eq!(*v2, 1);
21//! }
22//! let v3 = data.access();
23//! assert_eq!(*v3, 2);
24//! assert_eq!(*v1, 1);
25//! ```
26//!
27//! This is a primitive in a similar format to
28//! [Mutex](std::sync::Mutex), in that it wraps data for
29//! thread-safety, and provides access via guards.  A shared,
30//! reference copy of the data is stored. When reading, a handle to an
31//! immutable snapshot state is obtained, as an
32//! [Arc](std::sync::Arc). All readers who access this version of the
33//! data will receive handles to the same snapshot.
34//!
35//! To mutate the data, the reference copy is cloned into a mutable
36//! guard object.  The writer is free to make whatever changes they
37//! wish to this copy, and the new data will become the reference copy
38//! for all subsequent reads and writes, whenever the guard is
39//! dropped. No writes are visible whilst the guard is in scope.
40//!
41//! This is a somewhat niche primitive that has the following
42//! properties:
43//! - Readers can work with a coherent view for an extended period of
44//!   time, without preventing writers from making updates, or other
45//!   readers from seeing those updates.
46//! - There are no lifetimes to plumb through for the guards: the data
47//!   is owned. This is most significant before generic associated
48//!   types stabilise, but it will remain an advantage for the
49//!   simplicity of some use cases, compared to
50//!   [Mutex](std::sync::Mutex) or [RwLock](std::sync::RwLock).
51//! - Mutation is expensive. A full copy is made every time you create
52//!   a mutation guard by calling [mutate](CloneReplace::mutate) on
53//!   [CloneReplace].
54//! - The memory overhead can be large. For scenarios with very long
55//!   running readers, you may end up with many copies of your data
56//!   being stored simultaneously.
57//! - In the presence of multiple writers, it's entirely possible to
58//!   lose updates, because multiple writers are not prevented from
59//!   existing at the same time. Whatever state is set will always be
60//!   internally consistent, but you give up guaranteed external
61//!   consistency.
62
63use arc_swap::ArcSwap;
64use core::ops::{Deref, DerefMut, Drop};
65use std::fmt::{Display, Formatter, Result};
66use std::sync::Arc;
67
68/// A shareable store for data which provides owned references.
69///
70/// A `CloneReplace` stores a reference version of an enclosed data
71/// structure.  An owned snapshot of the current reference version can
72/// be retrieved by calling [access](CloneReplace::access) on
73/// [CloneReplace], which will preserve the reference version at that
74/// moment until it is dropped. A mutatable snapshot of the current
75/// reference version can be retrieved by calling
76/// [mutate](CloneReplace::mutate) on [CloneReplace], and when this
77/// goes out of scope, the reference version at that moment will be
78/// replaced by the mutated one.
79#[derive(Debug)]
80pub struct CloneReplace<T> {
81    data: Arc<ArcSwap<T>>,
82}
83
84impl<T> Clone for CloneReplace<T> {
85    fn clone(&self) -> Self {
86        Self {
87            data: self.data.clone(),
88        }
89    }
90}
91
92impl<T: Default> Default for CloneReplace<T> {
93    fn default() -> Self {
94        Self::new(Default::default())
95    }
96}
97
98impl<T> CloneReplace<T> {
99    /// Create a new [CloneReplace].
100    ///
101    /// Example:
102    /// ```rust
103    /// use clone_replace::CloneReplace;
104    ///
105    /// struct Foo {
106    ///    a: i32
107    /// }
108    ///
109    /// let cr = CloneReplace::new(Foo { a: 0 });
110    /// ```
111    pub fn new(data: T) -> Self {
112        Self {
113            data: Arc::new(ArcSwap::new(Arc::new(data))),
114        }
115    }
116
117    /// Retrieve a snapshot of the current reference version of the data.
118    ///
119    /// The return value is owned, and the snapshot taken will remain
120    /// unchanging until it goes out of scope. The existence of the
121    /// snapshot will not prevent the reference version from evolving,
122    /// so holding snapshots must be carefully considered, as it can
123    /// lead to memory pressure.
124    ///
125    /// Example:
126    /// ```rust
127    /// use clone_replace::CloneReplace;
128    ///
129    /// let c = CloneReplace::new(1);
130    /// let v = c.access();
131    /// assert_eq!(*v, 1);
132    /// ```
133    pub fn access(&self) -> Arc<T> {
134        self.data.load_full()
135    }
136
137    fn set_value(&self, value: T) {
138        self.data.swap(Arc::new(value));
139    }
140}
141
142impl<T: Clone> CloneReplace<T> {
143    /// Create a mutable replacement for the reference data.
144    ///
145    /// A copy of the current reference version of the data is
146    /// created. The [MutateGuard] provides mutable references to that
147    /// data. When the guard goes out of scope the reference version
148    /// will be overwritten with the updated version.
149    ///
150    /// Multiple guards can exist simultaneously, and there is no
151    /// attempt to prevent loss of data from stale updates.  An
152    /// internally consistent version of the data, as produced by a
153    /// single mutate call, will always exist, but not every mutate
154    /// call will end up being reflected in a reference version of the
155    /// data. This is a significantly weaker consistency guarantee
156    /// than a [Mutex](std::sync::Mutex) provides, for example.
157    ///
158    /// Example:
159    /// ```rust
160    /// use clone_replace::CloneReplace;
161    ///
162    /// let c = CloneReplace::new(1);
163    /// let mut v = c.mutate();
164    /// *v = 2;
165    /// drop(v);
166    /// assert_eq!(*c.access(), 2);
167    /// ```
168    pub fn mutate(&self) -> MutateGuard<T> {
169        let inner = &*self.data.load_full();
170        MutateGuard {
171            origin: self.clone(),
172            data: Some(inner.clone()),
173        }
174    }
175}
176
177/// A handle to a writeable version of the data.
178///
179/// This structure is created by the [mutate](CloneReplace::mutate)
180/// method on [CloneReplace]. The data held by the guard can be
181/// accessed via its [Deref] and [DerefMut] implementations.
182///
183/// When the guard is dropped, the contents will be written back to
184/// become the new reference version of the data. Any intermediate
185/// writes that occurred between the mutate guard being constructed
186/// and the writeback will be discarded.
187pub struct MutateGuard<T> {
188    origin: CloneReplace<T>,
189    data: Option<T>,
190}
191
192impl<T> MutateGuard<T> {
193    /// Discard the changes made in this mutation session.
194    ///
195    /// The changed data will not be written back to its origin.  If
196    /// you do not call discard, the changes will always be committed
197    /// when the guard goes out of scope.
198    ///
199    /// Example:
200    /// ```rust
201    /// use clone_replace::CloneReplace;
202    ///
203    /// let c = CloneReplace::new(1);
204    /// let mut v = c.mutate();
205    /// *v = 2;
206    /// v.discard();
207    /// assert_eq!(*c.access(), 1);
208    /// ```
209    pub fn discard(mut self) {
210        self.data = None;
211    }
212}
213
214impl<T> Deref for MutateGuard<T> {
215    type Target = T;
216    fn deref(&self) -> &Self::Target {
217        // Does not panic: the Option is only None after drop()
218        // returns, or if discard() has been called, which also drops
219        // the value immediately. There's no way to get here so long
220        // as we don't call deref() from those two methods.
221        self.data.as_ref().unwrap()
222    }
223}
224
225impl<T> DerefMut for MutateGuard<T> {
226    fn deref_mut(&mut self) -> &mut Self::Target {
227        // Does not panic: the Option is only None after drop()
228        // returns, or if discard() has been called, which also drops
229        // the value immediately. There's no way to get here so long
230        // as we don't call deref_mut() from those two methods.
231        self.data.as_mut().unwrap()
232    }
233}
234
235impl<T: Display> Display for MutateGuard<T> {
236    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
237        // Does not panic: the Option is only None after drop()
238        // returns, or if discard() has been called, which also drops
239        // the value immediately. There's no way to get here so long
240        // as we don't call fmt() from those two methods.
241        self.data.as_ref().unwrap().fmt(f)
242    }
243}
244
245impl<T> Drop for MutateGuard<T> {
246    fn drop(&mut self) {
247        if let Some(data) = self.data.take() {
248            self.origin.set_value(data);
249        }
250    }
251}
252
253#[cfg(test)]
254mod tests {
255    use super::CloneReplace;
256    use std::fmt::{Display, Formatter};
257
258    #[derive(Clone, Debug)]
259    struct Foo {
260        pub a: i32,
261    }
262
263    impl Display for Foo {
264        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
265            self.a.fmt(f)
266        }
267    }
268
269    #[test]
270    fn test_basic() {
271        let cr = CloneReplace::new(Foo { a: 0 });
272
273        let v1 = cr.access();
274        assert_eq!(v1.a, 0);
275        {
276            let mut m = cr.mutate();
277            assert_eq!(m.a, 0);
278            m.a = 2;
279            assert_eq!(m.a, 2);
280            let v2 = cr.access();
281            assert_eq!(v1.a, 0);
282            assert_eq!(v2.a, 0);
283        }
284        let v3 = cr.access();
285        assert_eq!(v3.a, 2);
286        assert_eq!(v1.a, 0);
287    }
288
289    #[test]
290    fn test_discard() {
291        let cr = CloneReplace::new(Foo { a: 5 });
292
293        let v1 = cr.access();
294        assert_eq!(v1.a, 5);
295        {
296            let mut m = cr.mutate();
297            assert_eq!(m.a, 5);
298            m.a = 1;
299            assert_eq!(m.a, 1);
300            let v2 = cr.access();
301            assert_eq!(v1.a, 5);
302            assert_eq!(v2.a, 5);
303            m.discard();
304        }
305        let v3 = cr.access();
306        assert_eq!(v3.a, 5);
307        assert_eq!(v1.a, 5);
308    }
309
310    #[test]
311    fn test_display() {
312        let cr = CloneReplace::new(Foo { a: 3 });
313
314        let v1 = cr.access();
315        assert_eq!(v1.to_string(), "3");
316        {
317            let mut m = cr.mutate();
318            assert_eq!(m.to_string(), "3");
319            m.a = 2;
320            assert_eq!(m.to_string(), "2");
321            let v2 = cr.access();
322            assert_eq!(v1.to_string(), "3");
323            assert_eq!(v2.to_string(), "3");
324        }
325        let v3 = cr.access();
326        assert_eq!(v3.to_string(), "2");
327        assert_eq!(v1.to_string(), "3");
328    }
329
330    #[test]
331    fn test_multiple_writers() {
332        let cr = CloneReplace::new(Foo { a: 4 });
333
334        let v1 = cr.access();
335        assert_eq!(v1.a, 4);
336        {
337            let mut m1 = cr.mutate();
338            let mut m2 = cr.mutate();
339
340            assert_eq!(m1.a, 4);
341            m1.a = 1;
342            assert_eq!(m1.a, 1);
343
344            let v2 = cr.access();
345            assert_eq!(v1.a, 4);
346            assert_eq!(v2.a, 4);
347
348            assert_eq!(m2.a, 4);
349            m2.a = 5;
350            assert_eq!(m2.a, 5);
351            let v3 = cr.access();
352            assert_eq!(v1.a, 4);
353            assert_eq!(v2.a, 4);
354            assert_eq!(v3.a, 4);
355            assert_eq!(m1.a, 1);
356        }
357        let v4 = cr.access();
358        assert_eq!(v4.a, 1);
359        assert_eq!(v1.a, 4);
360    }
361}