1use std::fmt::Debug;
2use std::sync::{Arc, Mutex, Weak};
3
4pub struct Arcm<T: Clone> {
7 inner: Arc<Mutex<T>>,
8}
9
10impl<T: Clone> Arcm<T> {
11 pub fn new(value: T) -> Self {
13 Self {
14 inner: Arc::new(Mutex::new(value)),
15 }
16 }
17
18 pub fn modify<F, R>(&self, f: F) -> R
20 where
21 F: FnOnce(&mut T) -> R,
22 {
23 let mut guard = self
24 .inner
25 .lock()
26 .unwrap_or_else(|poisoned| poisoned.into_inner());
27 f(&mut *guard)
28 }
29
30 pub fn value(&self) -> T {
32 match self.inner.lock() {
33 Ok(guard) => guard.clone(),
34 Err(poisoned) => poisoned.into_inner().clone(),
35 }
36 }
37
38 pub fn downgrade(&self) -> WeakArcm<T> {
40 WeakArcm {
41 inner: Arc::downgrade(&self.inner),
42 }
43 }
44
45 pub fn replace(&self, value: T) -> T {
47 let mut guard = match self.inner.lock() {
48 Ok(guard) => guard,
49 Err(poisoned) => poisoned.into_inner(),
50 };
51 std::mem::replace(&mut *guard, value)
52 }
53}
54
55impl<T: Clone> Clone for Arcm<T> {
56 fn clone(&self) -> Self {
57 Self {
58 inner: Arc::clone(&self.inner),
59 }
60 }
61}
62
63impl<T: Clone + Debug> Debug for Arcm<T> {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 f.debug_struct("Arcm").field("inner", &self.inner).finish()
66 }
67}
68
69impl<T: Clone + Default> Default for Arcm<T> {
70 fn default() -> Self {
71 Self::new(T::default())
72 }
73}
74
75impl<T: Clone> From<T> for Arcm<T> {
76 fn from(value: T) -> Self {
77 Self::new(value)
78 }
79}
80
81pub struct WeakArcm<T: Clone> {
83 inner: Weak<Mutex<T>>,
84}
85
86impl<T: Clone> WeakArcm<T> {
87 pub fn modify<F, R>(&self, f: F) -> Option<R>
89 where
90 F: FnOnce(&mut T) -> R,
91 {
92 self.inner.upgrade().map(|arc| {
93 let mut guard = arc.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
94 f(&mut *guard)
95 })
96 }
97
98 pub fn value(&self) -> Option<T> {
100 self.inner.upgrade().map(|arc| match arc.lock() {
101 Ok(guard) => guard.clone(),
102 Err(poisoned) => poisoned.into_inner().clone(),
103 })
104 }
105
106 pub fn replace(&self, value: T) -> Option<T> {
108 self.inner.upgrade().map(|arc| {
109 let mut guard = arc.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
110 std::mem::replace(&mut *guard, value)
111 })
112 }
113}
114
115impl<T: Clone> Debug for WeakArcm<T> {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 f.debug_struct("WeakArcm")
118 .field("inner", &self.inner)
119 .finish()
120 }
121}
122
123#[cfg(test)]
125mod tests {
126 use super::*;
127 use std::panic::{self, AssertUnwindSafe};
128 use std::thread;
129
130 #[test]
131 fn test_basic_usage() {
132 let v = Arcm::new(1);
133
134 v.modify(|v| *v = 42);
135 assert_eq!(v.value(), 42);
136 }
137
138 #[test]
139 fn test_multiple_references() {
140 let v1 = Arcm::new(1);
141 let v2 = v1.clone();
142
143 v1.modify(|v| *v = 42);
144 assert_eq!(v2.value(), 42);
145 }
146
147 #[test]
148 fn test_complex_modification() {
149 let numbers = Arcm::new(Vec::new());
150
151 numbers.modify(|v| v.push(1));
152 numbers.modify(|v| v.push(2));
153
154 assert_eq!(numbers.value(), vec![1, 2]);
155 }
156
157 #[test]
158 fn test_weak_reference() {
159 let strong = Arcm::new(42);
160 let weak = strong.downgrade();
161
162 assert_eq!(weak.value(), Some(42));
164
165 drop(strong);
167 assert_eq!(weak.value(), None);
168 }
169
170 #[test]
171 fn test_weak_modification() {
172 let strong = Arcm::new(vec![1, 2, 3]);
173 let weak = strong.downgrade();
174
175 let length = weak.modify(|v| {
177 v.push(4);
178 v.len()
179 });
180 assert_eq!(length, Some(4));
181 assert_eq!(strong.value(), vec![1, 2, 3, 4]);
182
183 drop(strong);
185 let result = weak.modify(|v| v.push(5));
186 assert_eq!(result, None);
187 }
188
189 #[test]
190 fn test_default() {
191 let vec_arcm: Arcm<Vec<i32>> = Arcm::default();
193 assert_eq!(vec_arcm.value(), Vec::new());
194
195 let int_arcm: Arcm<i32> = Arcm::default();
197 assert_eq!(int_arcm.value(), 0);
198
199 let string_arcm: Arcm<String> = Arcm::default();
201 assert_eq!(string_arcm.value(), String::new());
202 }
203
204 #[test]
205 fn test_from() {
206 let arcm1 = Arcm::from(42);
208 assert_eq!(arcm1.value(), 42);
209
210 let arcm2: Arcm<String> = "hello".to_string().into();
212 assert_eq!(arcm2.value(), "hello");
213
214 let arcm3: Arcm<Vec<i32>> = Vec::new().into();
216 assert!(arcm3.value().is_empty());
217 }
218
219 #[test]
220 fn test_arcm_poisoned_mutex_recovery() {
221 let arcm = Arcm::new(42);
222 let arcm_clone = arcm.clone();
223
224 let _ = panic::catch_unwind(AssertUnwindSafe(|| {
226 let handle = thread::spawn(move || {
227 arcm_clone.modify(|_| panic!("Deliberate panic to poison mutex"));
229 });
230
231 let _ = handle.join();
233 }));
234
235 let value = arcm.value();
237 assert_eq!(value, 42);
238
239 let result = arcm.modify(|v| {
241 *v = 100;
242 *v
243 });
244 assert_eq!(result, 100);
245 assert_eq!(arcm.value(), 100);
246 }
247
248 #[test]
249 fn test_arcm_replace() {
250 let arcm = Arcm::new(42);
251
252 let old_value = arcm.replace(100);
254 assert_eq!(old_value, 42);
255 assert_eq!(arcm.value(), 100);
256
257 let arcm2 = arcm.clone();
259 arcm.replace(200);
260 assert_eq!(arcm2.value(), 200);
261
262 let vec_arcm = Arcm::new(vec![1, 2, 3]);
264 let old_vec = vec_arcm.replace(vec![4, 5, 6]);
265 assert_eq!(old_vec, vec![1, 2, 3]);
266 assert_eq!(vec_arcm.value(), vec![4, 5, 6]);
267 }
268
269 #[test]
270 fn test_arcm_replace_with_poisoned_mutex() {
271 let arcm = Arcm::new(42);
272 let arcm_clone = arcm.clone();
273
274 let _ = panic::catch_unwind(AssertUnwindSafe(|| {
276 let handle = thread::spawn(move || {
277 arcm_clone.modify(|_| panic!("Deliberate panic to poison mutex"));
278 });
279 let _ = handle.join();
280 }));
281
282 let old_value = arcm.replace(100);
284 assert_eq!(old_value, 42);
285 assert_eq!(arcm.value(), 100);
286 }
287
288 #[test]
289 fn test_weak_arcm_poisoned_mutex() {
290 let strong = Arcm::new(42);
291 let weak = strong.downgrade();
292 let strong_clone = strong.clone();
293
294 let _ = panic::catch_unwind(AssertUnwindSafe(|| {
296 let handle = thread::spawn(move || {
297 strong_clone.modify(|_| panic!("Deliberate panic to poison mutex"));
298 });
299 let _ = handle.join();
300 }));
301
302 let value = weak.value();
304 assert_eq!(value, Some(42));
305
306 let result = weak.modify(|v| {
307 *v = 100;
308 *v
309 });
310 assert_eq!(result, Some(100));
311 assert_eq!(strong.value(), 100);
312 }
313
314 #[test]
315 fn test_weak_arcm_replace() {
316 let strong = Arcm::new(42);
317 let weak = strong.downgrade();
318
319 let old_value = weak.replace(100);
321 assert_eq!(old_value, Some(42));
322 assert_eq!(strong.value(), 100);
323
324 drop(strong);
326 let result = weak.replace(200);
327 assert_eq!(result, None); }
329
330 #[test]
331 fn test_weak_arcm_poisoned_and_replace() {
332 let strong = Arcm::new(42);
333 let weak = strong.downgrade();
334 let strong_clone = strong.clone();
335
336 let _ = panic::catch_unwind(AssertUnwindSafe(|| {
338 let handle = thread::spawn(move || {
339 strong_clone.modify(|_| panic!("Deliberate panic to poison mutex"));
340 });
341 let _ = handle.join();
342 }));
343
344 let old_value = weak.replace(100);
346 assert_eq!(old_value, Some(42));
347 assert_eq!(strong.value(), 100);
348 }
349
350 #[test]
351 fn test_arcm_thread_safety() {
352 let arcm = Arcm::new(0);
353 let threads = 10;
354 let increments_per_thread = 1000;
355
356 let handles: Vec<_> = (0..threads)
357 .map(|_| {
358 let arcm = arcm.clone();
359 thread::spawn(move || {
360 for _ in 0..increments_per_thread {
361 arcm.modify(|v| *v += 1);
362 }
363 })
364 })
365 .collect();
366
367 for handle in handles {
368 handle.join().unwrap();
369 }
370
371 assert_eq!(arcm.value(), threads * increments_per_thread);
372 }
373}