1use parking_lot::{const_mutex, Mutex};
17use std::mem;
18use std::ptr;
19
20pub struct WithLock<T> {
21 pub(crate) data: Mutex<T>,
22}
23
24impl<T> WithLock<T> {
25 pub fn with_lock<F, U>(&self, function: F) -> U
29 where
30 F: FnOnce(&mut T) -> U,
31 {
32 let mut lock = self.data.lock();
33 function(&mut *lock)
34 }
35
36 pub fn new<F>(data: F) -> WithLock<F> {
43 WithLock {
44 data: const_mutex(data),
45 }
46 }
47}
48
49pub struct MutexCell<T> {
50 pub(crate) data: WithLock<T>,
51}
52
53impl<T> MutexCell<T> {
54 pub fn new(data: T) -> MutexCell<T> {
62 MutexCell {
63 data: WithLock::<T>::new(data),
64 }
65 }
66
67 pub fn get(&self) -> T
69 where
70 T: Copy,
71 {
72 self.data.with_lock(|s| *s)
73 }
74
75 pub fn get_mut(&mut self) -> &mut T
77 where
78 T: Copy,
79 {
80 self.data.data.get_mut()
81 }
82
83 pub fn set(&self, data: T) {
85 self.data.with_lock(|s| *s = data);
86 }
87
88 pub fn replace(&self, val: T) -> T {
90 self.data.with_lock(|old| mem::replace(old, val))
91 }
92
93 pub fn swap(&self, new: &MutexCell<T>) {
95 if ptr::eq(self, new) {
96 return;
97 }
98 self.data
99 .with_lock(|a| new.data.with_lock(|b| mem::swap(a, b)))
100 }
101
102 pub fn take(&self) -> T
104 where
105 T: Default,
106 {
107 self.replace(T::default())
108 }
109
110 pub fn into_inner(self) -> T {
112 self.data.data.into_inner()
113 }
114}
115
116#[cfg(doctest)]
117#[doc = include_str!("../README.md")]
118mod readme {}
119
120#[cfg(test)]
121mod tests {
122 use crate::*;
123
124 struct SharedData {
125 pub a: i64,
126 pub b: i64,
127 }
128
129 #[test]
130 fn test_with_lock() {
131 let a = WithLock::<i64>::new(2);
132 let b = WithLock::<i64>::new(3);
133
134 let action_and_get = |s: &mut i64| *s;
135 let a_lock = a.with_lock(action_and_get);
136 let b_lock = b.with_lock(action_and_get);
137 assert_eq!(a_lock + b_lock, 5);
138
139 let a_lock_2 = a.with_lock(|s| *s);
141 let b_lock_2 = b.with_lock(|s| *s);
142 assert_eq!(a_lock_2 + b_lock_2, 5);
143 }
144
145 #[test]
146 fn test_with_lock_over_struct() {
147 let a = WithLock::<SharedData>::new(SharedData { a: 2, b: 2 });
148 let b = WithLock::<SharedData>::new(SharedData { a: 3, b: 3 });
149
150 let action_and_get = |s: &mut SharedData| (*s).a;
151 let a_lock = a.with_lock(action_and_get);
152 let b_lock = b.with_lock(action_and_get);
153 assert_eq!(a_lock + b_lock, 5);
154
155 let a_lock_2 = a.with_lock(|s| (*s).b);
157 let b_lock_2 = b.with_lock(|s| (*s).b);
158 assert_eq!(a_lock_2 + b_lock_2, 5);
159 }
160
161 #[test]
162 fn test_mutex_cell_no_deadlocks() {
163 let a = MutexCell::new(2);
164 let b = MutexCell::new(3);
165 let a_lock = a.get();
166 let b_lock = b.get();
167 assert_eq!(a_lock + b_lock, 5);
168 let a_lock_2 = a.get();
169 let b_lock_2 = b.get();
170 assert_eq!(a_lock_2 + b_lock_2, 5);
171 }
172
173 #[test]
174 fn test_mutex_cell_mutability() {
175 let cell = MutexCell::new(3);
176 assert_eq!(cell.get(), 3);
177 cell.set(4);
178 assert_eq!(cell.get(), 4);
179 }
180
181 #[test]
182 fn test_mutex_cell_replace() {
183 let cell = MutexCell::new(3);
184 assert_eq!(cell.replace(4), 3);
185 assert_eq!(cell.get(), 4);
186 }
187
188 #[test]
189 fn test_mutex_cell_swap() {
190 let c1 = MutexCell::new(5);
191 let c2 = MutexCell::new(10);
192 c1.swap(&c2);
193 assert_eq!(10, c1.get());
194 assert_eq!(5, c2.get());
195 }
196
197 #[test]
198 fn test_mutex_cell_swap_doesnt_deadlock() {
199 let c1 = MutexCell::new(5);
200 assert_eq!(c1.get(), 5);
201 c1.swap(&c1);
202 assert_eq!(c1.get(), 5);
203 }
204
205 #[test]
206 fn test_mutex_cell_get_mut() {
207 let mut c1 = MutexCell::new(5);
208 assert_eq!(c1.get(), 5);
209 let c2 = c1.get_mut();
210 *c2 += 1;
211 assert_eq!(c1.get(), 6);
212 }
213
214 #[test]
215 fn test_mutex_cell_take() {
216 let c = MutexCell::new(5);
217 let five = c.take();
218
219 assert_eq!(five, 5);
220 assert_eq!(c.into_inner(), 0);
221 }
222
223 #[test]
224 fn test_mutex_cell_into_inner() {
225 let c = MutexCell::new(5);
226 let five = c.into_inner();
227
228 assert_eq!(five, 5);
229 }
230}