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