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}