arc_guard/lib.rs
1//! # ArcGuard
2//!
3//! A Guard around `Arc<Mutex<T>>` allowing you to write less boilerplate code.
4//!
5//! # Example
6//!
7//! Before:
8//! ```
9//! use std::sync::{Arc, Mutex};
10//!
11//! let indicator = Arc::new(Mutex::new(Indicator::new()));
12//! let indicator_clone = indicator.clone();
13//! let indicator_clone = indicator_clone.lock().expect("Unable to lock indicator.");
14//!
15//! indicator_clone.do_something();
16//!
17//! drop(indicator_clone);
18//! ```
19//!
20//! After:
21//!
22//! ```
23//! use arc_guard::ArcGuard;
24//!
25//! let indicator = ArcGuard::new(Indicator::new());
26//!
27//! indicator.execute(|indicator| {
28//! let indicator = indicator.lock().expect("Unable to lock indicator.");
29//! indicator.do_something();
30//! });
31//! ```
32//!
33
34use std::sync::{Arc, Mutex};
35
36pub struct ArcGuard<T> {
37 arc: Arc<Mutex<T>>,
38}
39
40impl<T> ArcGuard<T> {
41 /// Constructs a new `ArcGuard<T>`.
42 ///
43 /// # Example
44 ///
45 /// ```
46 /// use arc_guard::ArcGuard;
47 ///
48 /// let indicator = ArcGuard::new(Indicator::new());
49 /// ```
50 pub fn new(t: T) -> Self {
51 ArcGuard{arc: Arc::new(Mutex::new(t))}
52 }
53
54 /// Executes a closure passed as an argument.
55 ///
56 /// This is exactly what helps us avoid the boilerplate code,
57 /// `execute` passes an `Arc<Mutex<T>>` clone and when the Closure finishes,
58 /// the clone is automatically dropped.
59 ///
60 /// # Example
61 ///
62 /// ```
63 /// use arc_guard::ArcGuard;
64 ///
65 /// let indicator = ArcGuard::new(Indicator::new());
66 ///
67 /// indicator.execute(|indicator| {
68 /// let indicator = indicator.lock().expect("Unable to lock indicator.");
69 /// indicator.do_something();
70 /// });
71 /// ```
72 ///
73 /// `execute` takes the return type of the Closure as its own,
74 /// so you are able to return from your closure into a variable.
75 ///
76 /// # Example
77 ///
78 /// ```
79 /// use arc_guard::ArcGuard;
80 ///
81 /// let indicator = ArcGuard::new(Indicator::new());
82 ///
83 /// let some_string: String = indicator.execute(|indicator| -> String {
84 /// let indicator = indicator.lock().expect("Unable to lock indicator.");
85 /// return indicator.something();
86 /// });
87 /// ```
88 pub fn execute<R>(&self, mut callback: impl FnMut(Arc<Mutex<T>>) -> R) -> R {
89 callback(self.arc.clone())
90 }
91
92 /// In some cases it is convenient to use `Arc<Mutex<T>>`, instead of `ArcGuard<T>`.
93 ///
94 /// With this method you are able to get a clone of the inner `Arc<Mutex<T>>`.
95 ///
96 /// # Example
97 ///
98 /// ```
99 /// use arc_guard::ArcGuard;
100 ///
101 /// let indicator = ArcGuard::new(Indicator::new());
102 ///
103 /// let inner_arc = indicator.arc();
104 /// ```
105 pub fn arc(&self) -> Arc<Mutex<T>> {
106 self.arc.clone()
107 }
108
109 /// Returns new `ArcGuard` with a clone of the inner `Arc<Mutex<T>>`.
110 ///
111 /// # Example
112 ///
113 /// ```
114 /// use arc_guard::ArcGuard;
115 ///
116 /// let indicator = ArcGuard::new(Indicator::new());
117 ///
118 /// let indicator_clone = indicator.clone();
119 /// ```
120 pub fn clone(&self) -> Self {
121 ArcGuard{arc: self.arc.clone()}
122 }
123}
124
125
126#[cfg(test)]
127mod tests {
128 use super::ArcGuard;
129 struct Indicator;
130
131 impl Indicator {
132 pub fn new() -> Self {Indicator}
133 }
134
135 #[test]
136 fn it_works() {
137 let indicator = ArcGuard::new(Indicator::new());
138
139 let string = indicator.execute(|indicator| -> String {
140 String::from("5")
141 });
142
143 assert_eq!(string, "5");
144 }
145}