thread_share/
locked.rs

1//! # Locked Module - ArcThreadShareLocked<T>
2//!
3//! This module provides `ArcThreadShareLocked<T>`, a safe zero-copy structure for
4//! data sharing between threads using read/write locks.
5//!
6//! ## 🚀 Overview
7//!
8//! `ArcThreadShareLocked<T>` is the **recommended alternative** to `ArcThreadShare<T>`
9//! when you need zero-copy operations with guaranteed thread safety. It provides
10//! the performance benefits of zero-copy while maintaining the safety guarantees
11//! of lock-based synchronization.
12//!
13//! ## Key Features
14//!
15//! - **Zero-Copy Operations**: No data cloning during access
16//! - **Guaranteed Thread Safety**: Uses `RwLock` for safe concurrent access
17//! - **High Performance**: Efficient `parking_lot` synchronization primitives
18//! - **Memory Efficiency**: Single copy of data shared across threads
19//! - **No Lost Updates**: All operations are guaranteed to succeed
20//! - **Predictable Behavior**: Consistent performance under all contention levels
21//!
22//! ## When to Use ArcThreadShareLocked<T>
23//!
24//! ### ✅ Perfect Use Cases
25//! - **Safe zero-copy operations** without the limitations of `ArcThreadShare<T>`
26//! - **High-frequency updates** where `ArcThreadShare<T>` would lose operations
27//! - **Critical data integrity** requirements
28//! - **Predictable performance** needs
29//! - **Large data structures** where cloning would be expensive
30//! - **Production applications** requiring reliability
31//!
32//! ### 🔄 Comparison with Other Patterns
33//!
34//! | Pattern | Zero-Copy | Thread Safety | Performance | Reliability |
35//! |---------|-----------|---------------|-------------|-------------|
36//! | **ThreadShare<T>** | ❌ | ✅ | Medium | ✅ |
37//! | **ArcThreadShare<T>** | ✅ | ⚠️ | High (unreliable) | ❌ |
38//! | **ArcThreadShareLocked<T>** | ✅ | ✅ | High | ✅ |
39//!
40//! ## Example Usage
41//!
42//! ### Basic Operations
43//! ```rust
44//! use thread_share::ArcThreadShareLocked;
45//!
46//! let counter = ArcThreadShareLocked::new(0);
47//!
48//! // Safe zero-copy operations
49//! counter.update(|x| *x += 1);
50//! counter.update(|x| *x += 2);
51//!
52//! assert_eq!(counter.get(), 3);
53//! ```
54//!
55//! ### From ThreadShare
56//! ```rust
57//! use thread_share::{share, ArcThreadShareLocked};
58//!
59//! let data = share!(String::from("Hello"));
60//! let arc_data = data.as_arc_locked();
61//! let locked_share = ArcThreadShareLocked::from_arc(arc_data);
62//!
63//! // Safe zero-copy with guaranteed thread safety
64//! locked_share.update(|s| s.push_str(" World"));
65//! ```
66//!
67//! ### High-Frequency Updates
68//! ```rust
69//! use thread_share::ArcThreadShareLocked;
70//! use std::thread;
71//!
72//! let counter = ArcThreadShareLocked::new(0);
73//! let clone = counter.clone();
74//!
75//! // Spawn multiple threads for high-frequency updates
76//! let handles: Vec<_> = (0..10).map(|_| {
77//!     let counter_clone = clone.clone();
78//!     thread::spawn(move || {
79//!         for _ in 0..10000 {
80//!             counter_clone.update(|x| *x += 1);
81//!         }
82//!     })
83//! }).collect();
84//!
85//! // Wait for all threads
86//! for handle in handles {
87//!     handle.join().unwrap();
88//! }
89//!
90//! // All updates are guaranteed to succeed
91//! assert_eq!(counter.get(), 100000);
92//! ```
93//!
94//! ## Performance Characteristics
95//!
96//! - **Low Contention**: Excellent performance, minimal overhead
97//! - **Medium Contention**: Good performance with some lock contention
98//! - **High Contention**: Consistent performance, no lost operations
99//! - **Memory Usage**: Minimal overhead from lock structures
100//! - **Scalability**: Scales well with thread count
101//!
102//! ## Thread Safety
103//!
104//! `ArcThreadShareLocked<T>` automatically implements `Send` and `Sync` traits,
105//! making it safe to use across thread boundaries. The internal `RwLock` ensures
106//! that all operations are thread-safe and no data races can occur.
107//!
108//! ## Memory Management
109//!
110//! - **Arc**: Provides reference counting for shared ownership
111//! - **RwLock**: Ensures exclusive write access and concurrent read access
112//! - **No Box Allocation**: Unlike `ArcThreadShare<T>`, no per-operation allocations
113//! - **Efficient Locking**: Uses `parking_lot` for optimal performance
114//!
115//! ## Best Practices
116//!
117//! 1. **Use for zero-copy needs**: When you need to avoid cloning data
118//! 2. **Prefer over ArcThreadShare**: For reliable, production applications
119//! 3. **Monitor lock contention**: Use `read()` and `write()` methods appropriately
120//! 4. **Keep critical sections short**: Minimize time spent holding locks
121//! 5. **Use descriptive variable names**: Make it clear this is the locked version
122//!
123//! ## Migration from ArcThreadShare<T>
124//!
125//! If you're currently using `ArcThreadShare<T>` and experiencing issues:
126//!
127//! ```rust
128//! // Old: Unreliable atomic operations
129//! use thread_share::ArcThreadShare;
130//! let arc_share = ArcThreadShare::new(0);
131//! arc_share.update(|x| *x += 1); // May fail under contention
132//!
133//! // New: Reliable locked operations
134//! use thread_share::ArcThreadShareLocked;
135//! let locked_share = ArcThreadShareLocked::new(0);
136//! locked_share.update(|x| *x += 1); // Always succeeds
137//! ```
138//!
139//! ## Error Handling
140//!
141//! Unlike `ArcThreadShare<T>`, `ArcThreadShareLocked<T>` operations never fail
142//! due to contention. All operations are guaranteed to complete successfully,
143//! making error handling much simpler.
144//!
145//! ## Integration with ThreadShare
146//!
147//! `ArcThreadShareLocked<T>` integrates seamlessly with `ThreadShare<T>`:
148//!
149//! ```rust
150//! use thread_share::{share, ArcThreadShareLocked};
151//!
152//! let data = share!(vec![1, 2, 3]);
153//!
154//! // Get locked version for zero-copy operations
155//! let arc_data = data.as_arc_locked();
156//! let locked_share = ArcThreadShareLocked::from_arc(arc_data);
157//!
158//! // Use locked version in threads
159//! locked_share.update(|v| v.push(4));
160//!
161//! // Changes are visible in original ThreadShare
162//! assert_eq!(data.get(), vec![1, 2, 3, 4]);
163//! ```
164
165use parking_lot::RwLock;
166use std::sync::Arc;
167
168#[cfg(feature = "serialize")]
169use serde::{de::DeserializeOwned};
170
171/// Helper structure for working with Arc<RwLock<T>> directly (with locks)
172///
173/// `ArcThreadShareLocked<T>` is the **recommended alternative** to `ArcThreadShare<T>`
174/// when you need zero-copy operations with guaranteed thread safety. It provides
175/// the performance benefits of zero-copy while maintaining the safety guarantees
176/// of lock-based synchronization.
177///
178/// ## Key Features
179///
180/// - **Zero-Copy Operations**: No data cloning during access
181/// - **Guaranteed Thread Safety**: Uses `RwLock` for safe concurrent access
182/// - **High Performance**: Efficient `parking_lot` synchronization primitives
183/// - **Memory Efficiency**: Single copy of data shared across threads
184/// - **No Lost Updates**: All operations are guaranteed to succeed
185/// - **Predictable Behavior**: Consistent performance under all contention levels
186///
187/// ## When to Use
188///
189/// - **Safe zero-copy operations** without the limitations of `ArcThreadShare<T>`
190/// - **High-frequency updates** where `ArcThreadShare<T>` would lose operations
191/// - **Critical data integrity** requirements
192/// - **Predictable performance** needs
193/// - **Production applications** requiring reliability
194///
195/// ## Example
196///
197/// ```rust
198/// use thread_share::ArcThreadShareLocked;
199///
200/// let counter = ArcThreadShareLocked::new(0);
201///
202/// // Safe zero-copy operations
203/// counter.update(|x| *x += 1);
204/// counter.update(|x| *x += 2);
205///
206/// assert_eq!(counter.get(), 3);
207/// ```
208///
209/// ## Performance
210///
211/// - **Low Contention**: Excellent performance, minimal overhead
212/// - **Medium Contention**: Good performance with some lock contention
213/// - **High Contention**: Consistent performance, no lost operations
214/// - **Memory Usage**: Minimal overhead from lock structures
215/// - **Scalability**: Scales well with thread count
216pub struct ArcThreadShareLocked<T> {
217    pub data: Arc<RwLock<T>>,
218}
219
220// Automatically implement Send and Sync for ArcThreadShareLocked
221unsafe impl<T> Send for ArcThreadShareLocked<T> {}
222unsafe impl<T> Sync for ArcThreadShareLocked<T> {}
223
224impl<T> Clone for ArcThreadShareLocked<T> {
225    fn clone(&self) -> Self {
226        Self {
227            data: Arc::clone(&self.data),
228        }
229    }
230}
231
232impl<T> ArcThreadShareLocked<T> {
233    /// Creates a new ArcThreadShareLocked with data
234    ///
235    /// This method creates a new `ArcThreadShareLocked<T>` instance with the provided data.
236    /// The data is wrapped in an `Arc<RwLock<T>>` for thread-safe sharing.
237    ///
238    /// ## Arguments
239    ///
240    /// * `data` - The initial data to share between threads
241    ///
242    /// ## Returns
243    ///
244    /// A new `ArcThreadShareLocked<T>` instance containing the data.
245    ///
246    /// ## Example
247    ///
248    /// ```rust
249    /// use thread_share::ArcThreadShareLocked;
250    ///
251    /// let counter = ArcThreadShareLocked::new(0);
252    /// let message = ArcThreadShareLocked::new(String::from("Hello"));
253    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
254    /// ```
255    pub fn new(data: T) -> Self {
256        let arc = Arc::new(RwLock::new(data));
257        Self { data: arc }
258    }
259
260    /// Creates from Arc<RwLock<T>>
261    ///
262    /// This method creates an `ArcThreadShareLocked<T>` from an existing `Arc<RwLock<T>>`.
263    /// Useful when you already have locked data from other sources, such as
264    /// from `ThreadShare<T>::as_arc_locked()`.
265    ///
266    /// ## Arguments
267    ///
268    /// * `arc` - An `Arc<RwLock<T>>` containing the data to share
269    ///
270    /// ## Returns
271    ///
272    /// A new `ArcThreadShareLocked<T>` instance sharing the same data.
273    ///
274    /// ## Example
275    ///
276    /// ```rust
277    /// use thread_share::{share, ArcThreadShareLocked};
278    ///
279    /// let data = share!(vec![1, 2, 3]);
280    /// let arc_data = data.as_arc_locked();
281    /// let locked_share = ArcThreadShareLocked::from_arc(arc_data);
282    ///
283    /// // Now you can use safe zero-copy operations
284    /// locked_share.update(|v| v.push(4));
285    /// ```
286    pub fn from_arc(arc: Arc<RwLock<T>>) -> Self {
287        Self { data: arc }
288    }
289
290    /// Gets a copy of data
291    ///
292    /// This method retrieves a copy of the current data. The operation is safe
293    /// but involves cloning the data.
294    ///
295    /// ## Requirements
296    ///
297    /// The type `T` must implement `Clone` trait.
298    ///
299    /// ## Returns
300    ///
301    /// A copy of the current data.
302    ///
303    /// ## Example
304    ///
305    /// ```rust
306    /// use thread_share::ArcThreadShareLocked;
307    ///
308    /// let counter = ArcThreadShareLocked::new(42);
309    /// let value = counter.get();
310    /// assert_eq!(value, 42);
311    /// ```
312    pub fn get(&self) -> T
313    where
314        T: Clone,
315    {
316        self.data.read().clone()
317    }
318
319    /// Gets a reference to data (no cloning!)
320    ///
321    /// This method provides read-only access to the data without cloning.
322    /// The returned guard holds the read lock until it's dropped.
323    ///
324    /// ## Returns
325    ///
326    /// A read guard that provides access to the data.
327    ///
328    /// ## Example
329    ///
330    /// ```rust
331    /// use thread_share::ArcThreadShareLocked;
332    ///
333    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
334    ///
335    /// // Get reference without cloning
336    /// {
337    ///     let guard = data.get_ref();
338    ///     assert_eq!(guard.len(), 3);
339    ///     assert_eq!(guard[0], 1);
340    ///     // Guard is automatically dropped here, releasing the lock
341    /// }
342    /// ```
343    ///
344    /// ## Note
345    ///
346    /// This method will block until the read lock can be acquired.
347    /// Multiple threads can read simultaneously.
348    /// For non-blocking behavior, use `try_get_ref()`.
349    pub fn get_ref(&self) -> parking_lot::RwLockReadGuard<'_, T> {
350        self.data.read()
351    }
352
353    /// Tries to get a reference to data without blocking
354    ///
355    /// This method attempts to acquire a read lock without blocking.
356    /// Returns `None` if the lock cannot be acquired immediately.
357    ///
358    /// ## Returns
359    ///
360    /// `Some(guard)` if the lock was acquired, `None` if it couldn't be acquired.
361    ///
362    /// ## Example
363    ///
364    /// ```rust
365    /// use thread_share::ArcThreadShareLocked;
366    ///
367    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
368    ///
369    /// // Try to get reference without blocking
370    /// if let Some(guard) = data.try_get_ref() {
371    ///     assert_eq!(guard.len(), 3);
372    ///     assert_eq!(guard[0], 1);
373    ///     // Guard is automatically dropped here
374    /// } else {
375    ///     // Lock was not available
376    /// }
377    ///
378    /// // Ensure data is still accessible
379    /// assert_eq!(data.get(), vec![1, 2, 3]);
380    /// ```
381    pub fn try_get_ref(&self) -> Option<parking_lot::RwLockReadGuard<'_, T>> {
382        self.data.try_read()
383    }
384
385    /// Gets a mutable reference to data (no cloning!)
386    ///
387    /// This method provides mutable access to the data without cloning.
388    /// The returned guard holds the write lock until it's dropped.
389    ///
390    /// ## Returns
391    ///
392    /// A write guard that provides mutable access to the data.
393    ///
394    /// ## Example
395    ///
396    /// ```rust
397    /// use thread_share::ArcThreadShareLocked;
398    ///
399    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
400    ///
401    /// // Get mutable reference without cloning
402    /// {
403    ///     let mut guard = data.get_mut();
404    ///     guard.push(4);
405    ///     // Guard is automatically dropped here, releasing the lock
406    /// }
407    ///
408    /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
409    /// ```
410    ///
411    /// ## Warning
412    ///
413    /// This method will block until the write lock can be acquired.
414    /// In high-contention scenarios, this can cause delays.
415    /// For non-blocking behavior, use `try_get_mut()`.
416    ///
417    /// ## Best Practices
418    ///
419    /// - Keep critical sections short to minimize lock contention
420    /// - Always drop the guard explicitly in complex scenarios
421    /// - Consider using `try_get_mut()` for non-blocking operations
422    pub fn get_mut(&self) -> parking_lot::RwLockWriteGuard<'_, T> {
423        self.data.write()
424    }
425
426    /// Tries to get a mutable reference to data without blocking
427    ///
428    /// This method attempts to acquire a write lock without blocking.
429    /// Returns `None` if the lock cannot be acquired immediately.
430    ///
431    /// ## Returns
432    ///
433    /// `Some(guard)` if the lock was acquired, `None` if it couldn't be acquired.
434    ///
435    /// ## Example
436    ///
437    /// ```rust
438    /// use thread_share::ArcThreadShareLocked;
439    ///
440    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
441    ///
442    /// // Try to get mutable reference without blocking
443    /// if let Some(mut guard) = data.try_get_mut() {
444    ///     guard.push(4);
445    ///     // Guard is automatically dropped here
446    /// }
447    ///
448    /// // Ensure data is still accessible
449    /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
450    /// ```
451    pub fn try_get_mut(&self) -> Option<parking_lot::RwLockWriteGuard<'_, T>> {
452        self.data.try_write()
453    }
454
455    /// Sets data
456    ///
457    /// This method replaces the current data with new data.
458    ///
459    /// ## Arguments
460    ///
461    /// * `new_data` - The new data to set
462    ///
463    /// ## Example
464    ///
465    /// ```rust
466    /// use thread_share::ArcThreadShareLocked;
467    ///
468    /// let counter = ArcThreadShareLocked::new(0);
469    /// counter.set(100);
470    /// assert_eq!(counter.get(), 100);
471    /// ```
472    pub fn set(&self, new_data: T) {
473        let mut data = self.data.write();
474        *data = new_data;
475    }
476
477    /// Updates data using a function
478    ///
479    /// This method allows you to modify the data through a closure.
480    /// The operation is guaranteed to succeed and is thread-safe.
481    ///
482    /// ## Arguments
483    ///
484    /// * `f` - Closure that receives a mutable reference to the data
485    ///
486    /// ## Example
487    ///
488    /// ```rust
489    /// use thread_share::ArcThreadShareLocked;
490    ///
491    /// let counter = ArcThreadShareLocked::new(0);
492    ///
493    /// counter.update(|x| *x += 1);
494    /// assert_eq!(counter.get(), 1);
495    ///
496    /// counter.update(|x| *x *= 2);
497    /// assert_eq!(counter.get(), 2);
498    /// ```
499    pub fn update<F>(&self, f: F)
500    where
501        F: FnOnce(&mut T),
502    {
503        let mut data = self.data.write();
504        f(&mut data);
505    }
506
507    /// Reads data through a function
508    ///
509    /// This method provides read-only access to the data through a closure.
510    /// Multiple threads can read simultaneously.
511    ///
512    /// ## Arguments
513    ///
514    /// * `f` - Closure that receives a reference to the data
515    ///
516    /// ## Returns
517    ///
518    /// The result of the closure execution.
519    ///
520    /// ## Example
521    ///
522    /// ```rust
523    /// use thread_share::ArcThreadShareLocked;
524    ///
525    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
526    ///
527    /// let length = data.read(|v| v.len());
528    /// assert_eq!(length, 3);
529    ///
530    /// let sum: i32 = data.read(|v| v.iter().sum());
531    /// assert_eq!(sum, 6);
532    /// ```
533    pub fn read<F, R>(&self, f: F) -> R
534    where
535        F: FnOnce(&T) -> R,
536    {
537        let data = self.data.read();
538        f(&data)
539    }
540
541    /// Writes data through a function
542    ///
543    /// This method provides mutable access to the data through a closure.
544    /// Only one thread can write at a time.
545    ///
546    /// ## Arguments
547    ///
548    /// * `f` - Closure that receives a mutable reference to the data
549    ///
550    /// ## Returns
551    ///
552    /// The result of the closure execution.
553    ///
554    /// ## Example
555    ///
556    /// ```rust
557    /// use thread_share::ArcThreadShareLocked;
558    ///
559    /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
560    ///
561    /// let length = data.write(|v| {
562    ///     v.push(4);
563    ///     v.len()
564    /// });
565    ///
566    /// assert_eq!(length, 4);
567    /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
568    /// ```
569    pub fn write<F, R>(&self, f: F) -> R
570    where
571        F: FnOnce(&mut T) -> R,
572    {
573        let mut data = self.data.write();
574        f(&mut data)
575    }
576
577    #[cfg(feature = "serialize")]
578    pub fn to_json(&self) -> Result<String, serde_json::Error>
579    where
580        T: serde::Serialize + Clone,
581    {
582        serde_json::to_string(&self.get())
583    }
584
585    #[cfg(feature = "serialize")]
586    pub fn from_json<D: DeserializeOwned>(&self, json: &str) -> Result<D, serde_json::Error> {
587        serde_json::from_str(json)
588    }
589}