1use std::sync::{Arc, RwLock};
4
5use educe::Educe;
6
7use crate::{Error, Result};
8
9#[derive(Debug, Educe)]
18#[educe(Default)]
19#[cfg_attr(docsrs, doc(cfg(feature = "experimental-api")))]
20#[cfg_attr(not(feature = "experimental-api"), allow(unreachable_pub))]
21pub struct SharedMutArc<T> {
22 dir: RwLock<Option<Arc<T>>>,
27}
28
29#[cfg_attr(not(feature = "experimental-api"), allow(unreachable_pub))]
30impl<T> SharedMutArc<T> {
31 pub fn new() -> Self {
33 SharedMutArc::default()
34 }
35
36 pub fn replace(&self, new_val: T) {
38 let mut w = self
39 .dir
40 .write()
41 .expect("Poisoned lock for directory reference");
42 *w = Some(Arc::new(new_val));
43 }
44
45 #[allow(unused)]
47 pub(crate) fn clear(&self) {
48 let mut w = self
49 .dir
50 .write()
51 .expect("Poisoned lock for directory reference");
52 *w = None;
53 }
54
55 pub fn get(&self) -> Option<Arc<T>> {
57 let r = self
58 .dir
59 .read()
60 .expect("Poisoned lock for directory reference");
61 r.as_ref().map(Arc::clone)
62 }
63
64 pub fn mutate<F, U>(&self, func: F) -> Result<U>
79 where
80 F: FnOnce(&mut T) -> Result<U>,
81 T: Clone,
82 {
83 let mut writeable = self
84 .dir
85 .write()
86 .expect("Poisoned lock for directory reference");
87 let dir = writeable.as_mut();
88 match dir {
89 None => Err(Error::DirectoryNotPresent), Some(arc) => func(Arc::make_mut(arc)),
91 }
92 }
93}
94
95#[cfg(test)]
96mod test {
97 #![allow(clippy::bool_assert_comparison)]
99 #![allow(clippy::clone_on_copy)]
100 #![allow(clippy::dbg_macro)]
101 #![allow(clippy::mixed_attributes_style)]
102 #![allow(clippy::print_stderr)]
103 #![allow(clippy::print_stdout)]
104 #![allow(clippy::single_char_pattern)]
105 #![allow(clippy::unwrap_used)]
106 #![allow(clippy::unchecked_duration_subtraction)]
107 #![allow(clippy::useless_vec)]
108 #![allow(clippy::needless_pass_by_value)]
109 use super::*;
111 #[test]
112 fn shared_mut_arc() {
113 let val: SharedMutArc<Vec<u32>> = SharedMutArc::new();
114 assert_eq!(val.get(), None);
115
116 val.replace(Vec::new());
117 assert_eq!(val.get().unwrap().as_ref()[..], Vec::<u32>::new());
118
119 val.mutate(|v| {
120 v.push(99);
121 Ok(())
122 })
123 .unwrap();
124 assert_eq!(val.get().unwrap().as_ref()[..], [99]);
125
126 val.clear();
127 assert_eq!(val.get(), None);
128
129 assert!(val
130 .mutate(|v| {
131 v.push(99);
132 Ok(())
133 })
134 .is_err());
135 }
136}