snaplock/std_impl.rs
1use crate::{SnapshotLock, SnapshotLockReadGuard, SnapshotLockWriteGuard};
2use arc_swap::ArcSwap;
3use std::marker::PhantomData;
4use std::ops::Deref;
5use std::sync::atomic::{AtomicUsize, Ordering};
6use std::sync::{Arc, RwLock, RwLockWriteGuard};
7
8impl<T: Clone> SnapshotLock<T, RwLock<(T, usize)>> {
9 /// Creates a new `SnapshotLock` with the initial value.
10 ///
11 /// # Arguments
12 ///
13 /// * `inner` - The initial value to be protected by the lock.
14 ///
15 /// # Examples
16 ///
17 /// ```
18 /// use snaplock::SnapshotLock;
19 ///
20 /// let lock = SnapshotLock::new(42);
21 /// assert_eq!(*lock.read(), 42);
22 /// ```
23 pub fn new(inner: T) -> Self {
24 Self {
25 inner: RwLock::new((inner.clone(), 0)),
26 latest: ArcSwap::new(Arc::new(inner)),
27 latest_version: AtomicUsize::new(0),
28 }
29 }
30
31 /// Acquires an exclusive write lock on the protected data.
32 ///
33 /// This method blocks until no other writers hold the lock. The returned
34 /// `SnapshotLockWriteGuard` allows mutable access to the data. When the guard is
35 /// dropped, the version number is incremented and subsequent reads will
36 /// see the updated value.
37 ///
38 /// # Returns
39 ///
40 /// A `SnapshotLockWriteGuard` that provides mutable access to the data.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use snaplock::SnapshotLock;
46 ///
47 /// let lock = SnapshotLock::new(0);
48 /// {
49 /// let mut guard = lock.write();
50 /// *guard = 42;
51 /// } // Guard dropped here, version incremented
52 /// assert_eq!(*lock.read(), 42);
53 /// ```
54 pub fn write(&self) -> SnapshotLockWriteGuard<'_, T, RwLockWriteGuard<'_, (T, usize)>> {
55 let mut guard = self.inner.write().unwrap();
56 guard.1 += 1; // increment version
57 SnapshotLockWriteGuard(guard, PhantomData)
58 }
59
60 /// Acquires a shared read lock on the protected data.
61 ///
62 /// This method attempts to get the latest version of the data with minimal
63 /// blocking. It first tries a non-blocking read of the current version,
64 /// and if that fails or detects a newer version, it falls back to a
65 /// cached snapshot.
66 ///
67 /// # Returns
68 ///
69 /// A `SnapshotLockReadGuard` that provides immutable access to a snapshot of the data.
70 ///
71 /// # Examples
72 ///
73 /// ```
74 /// use snaplock::SnapshotLock;
75 ///
76 /// let lock = SnapshotLock::new("data");
77 /// let guard = lock.read();
78 /// assert_eq!(*guard, "data");
79 /// ```
80 pub fn read(&self) -> SnapshotLockReadGuard<T> {
81 if let Ok(read) = self.inner.try_read() {
82 let (data, version) = read.deref();
83 if self.latest_version.swap(*version, Ordering::Acquire) < *version {
84 self.latest.store(Arc::new(data.clone()));
85 }
86 }
87
88 SnapshotLockReadGuard(arc_swap::Guard::into_inner(self.latest.load()))
89 }
90}