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}