1use std::fmt::Debug;
14use std::ops::{Deref, DerefMut};
15
16#[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
18use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak};
19
20#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
22use std::cell::{Ref, RefCell, RefMut};
23#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
24use std::rc::{Rc, Weak};
25
26
27#[derive(Debug)]
35pub struct SharedContainer<T: Debug> {
36 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
38 inner: Arc<RwLock<T>>,
39
40 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
42 inner: Rc<RefCell<T>>,
43}
44
45#[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
47unsafe impl<T: Debug + Send> Send for SharedContainer<T> {}
48
49#[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
50unsafe impl<T: Debug + Send + Sync> Sync for SharedContainer<T> {}
51
52#[derive(Debug)]
60pub struct WeakSharedContainer<T: Debug> {
61 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
63 inner: Weak<RwLock<T>>,
64
65 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
67 inner: Weak<RefCell<T>>,
68}
69
70impl<T: Debug> Clone for WeakSharedContainer<T> {
71 fn clone(&self) -> Self {
72 WeakSharedContainer {
74 inner: self.inner.clone(),
75 }
76 }
77}
78
79impl<T: Debug + PartialEq> PartialEq for SharedContainer<T> {
80 fn eq(&self, other: &Self) -> bool {
81 match (self.read(), other.read()) {
82 (Some(self_val), Some(other_val)) => *self_val == *other_val,
83 _ => false,
84 }
85 }
86}
87
88impl<T: Debug> Clone for SharedContainer<T> {
89 fn clone(&self) -> Self {
90 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
91 {
92 SharedContainer {
93 inner: Arc::clone(&self.inner),
94 }
95 }
96
97 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
98 {
99 SharedContainer {
100 inner: Rc::clone(&self.inner),
101 }
102 }
103 }
104}
105
106impl<T: Debug + Clone> SharedContainer<T> {
107 pub fn get_cloned(&self) -> Option<T> {
115 let guard = self.read()?;
116 Some((*guard).clone())
117 }
118}
119
120impl<T: Debug> SharedContainer<T> {
121 pub fn new(value: T) -> Self {
129 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
130 {
131 SharedContainer {
132 inner: Arc::new(RwLock::new(value)),
133 }
134 }
135
136 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
137 {
138 SharedContainer {
139 inner: Rc::new(RefCell::new(value)),
140 }
141 }
142 }
143
144 pub fn read(&self) -> Option<SharedReadGuard<T>> {
150 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
151 {
152 match self.inner.read() {
153 Ok(guard) => Some(SharedReadGuard::Multi(guard)),
154 Err(_) => None,
155 }
156 }
157
158 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
159 {
160 match self.inner.try_borrow() {
161 Ok(borrow) => Some(SharedReadGuard::Single(borrow)),
162 Err(_) => None,
163 }
164 }
165 }
166
167 pub fn write(&self) -> Option<SharedWriteGuard<T>> {
173 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
174 {
175 match self.inner.write() {
176 Ok(guard) => Some(SharedWriteGuard::Multi(guard)),
177 Err(_) => None,
178 }
179 }
180
181 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
182 {
183 match self.inner.try_borrow_mut() {
184 Ok(borrow) => Some(SharedWriteGuard::Single(borrow)),
185 Err(_) => None,
186 }
187 }
188 }
189
190 pub fn downgrade(&self) -> WeakSharedContainer<T> {
198 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
199 {
200 WeakSharedContainer {
201 inner: Arc::downgrade(&self.inner),
202 }
203 }
204
205 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
206 {
207 WeakSharedContainer {
208 inner: Rc::downgrade(&self.inner),
209 }
210 }
211 }
212}
213
214impl<T: Debug> WeakSharedContainer<T> {
215 pub fn upgrade(&self) -> Option<SharedContainer<T>> {
224 self.inner.upgrade().map(|inner| SharedContainer { inner })
226 }
227}
228pub enum SharedReadGuard<'a, T: Debug> {
235 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
236 Multi(RwLockReadGuard<'a, T>),
237
238 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
239 Single(Ref<'a, T>),
240}
241
242impl<'a, T: Debug> Deref for SharedReadGuard<'a, T> {
243 type Target = T;
244
245 fn deref(&self) -> &Self::Target {
246 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
247 {
248 match self {
249 SharedReadGuard::Multi(guard) => guard.deref(),
250 }
251 }
252
253 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
254 {
255 match self {
256 SharedReadGuard::Single(borrow) => borrow.deref(),
257 }
258 }
259 }
260}
261
262pub enum SharedWriteGuard<'a, T: Debug> {
269 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
270 Multi(RwLockWriteGuard<'a, T>),
271
272 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
273 Single(RefMut<'a, T>),
274}
275
276impl<'a, T: Debug> Deref for SharedWriteGuard<'a, T> {
277 type Target = T;
278
279 fn deref(&self) -> &Self::Target {
280 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
281 {
282 match self {
283 SharedWriteGuard::Multi(guard) => guard.deref(),
284 }
285 }
286
287 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
288 {
289 match self {
290 SharedWriteGuard::Single(borrow) => borrow.deref(),
291 }
292 }
293 }
294}
295
296impl<'a, T: Debug> DerefMut for SharedWriteGuard<'a, T> {
297 fn deref_mut(&mut self) -> &mut Self::Target {
298 #[cfg(all(not(target_arch = "wasm32"), not(feature = "force-wasm-impl")))]
299 {
300 match self {
301 SharedWriteGuard::Multi(guard) => guard.deref_mut(),
302 }
303 }
304
305 #[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
306 {
307 match self {
308 SharedWriteGuard::Single(borrow) => borrow.deref_mut(),
309 }
310 }
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[derive(Debug, Clone, PartialEq)]
319 struct TestStruct {
320 value: i32,
321 }
322
323 #[test]
324 fn test_read_access() {
325 let container = SharedContainer::new(TestStruct { value: 42 });
326
327 let guard = container.read().unwrap();
329 assert_eq!(guard.value, 42);
330 }
331
332 #[test]
333 fn test_write_access() {
334 let container = SharedContainer::new(TestStruct { value: 42 });
335
336 {
338 let mut guard = container.write().unwrap();
339 guard.value = 100;
340 }
341
342 let guard = container.read().unwrap();
344 assert_eq!(guard.value, 100);
345 }
346
347 #[test]
348 fn test_clone_container() {
349 let container1 = SharedContainer::new(TestStruct { value: 42 });
350 let container2 = container1.clone();
351
352 {
354 let mut guard = container2.write().unwrap();
355 guard.value = 100;
356 }
357
358 let guard = container1.read().unwrap();
360 assert_eq!(guard.value, 100);
361 }
362
363 #[test]
364 fn test_get_cloned() {
365 let container = SharedContainer::new(TestStruct { value: 42 });
366 let cloned = container.get_cloned().unwrap();
367 assert_eq!(cloned, TestStruct { value: 42 });
368
369 {
371 let mut guard = container.write().unwrap();
372 guard.value = 100;
373 }
374
375 assert_eq!(cloned, TestStruct { value: 42 });
377
378 let new_clone = container.get_cloned().unwrap();
380 assert_eq!(new_clone, TestStruct { value: 100 });
381 }
382
383 #[test]
384 fn test_weak_ref() {
385 let container = SharedContainer::new(TestStruct { value: 42 });
386
387 let weak = container.downgrade();
389
390 let container2 = weak.upgrade().unwrap();
392
393 {
395 let mut guard = container2.write().unwrap();
396 guard.value = 100;
397 }
398
399 {
401 let guard = container.read().unwrap();
402 assert_eq!(guard.value, 100);
403 }
404 drop(container);
406 drop(container2);
407
408 assert!(weak.upgrade().is_none());
410 }
411
412 #[test]
413 fn test_weak_clone() {
414 let container = SharedContainer::new(TestStruct { value: 42 });
415
416 let weak1 = container.downgrade();
418 let weak2 = weak1.clone();
419
420 let container1 = weak1.upgrade().unwrap();
422 let container2 = weak2.upgrade().unwrap();
423
424 {
426 let mut guard = container2.write().unwrap();
427 guard.value = 100;
428 }
429
430 {
432 let guard = container1.read().unwrap();
433 assert_eq!(guard.value, 100);
434 }
435
436 drop(container);
438 drop(container1);
439 drop(container2);
440
441 assert!(weak1.upgrade().is_none());
443 assert!(weak2.upgrade().is_none());
444 }
445}
446
447#[cfg(test)]
450#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
451mod wasm_tests {
452 use super::*;
453
454 #[derive(Debug, Clone, PartialEq)]
455 struct TestStruct {
456 value: i32,
457 }
458
459 #[test]
460 fn test_wasm_read_access() {
461 let container = SharedContainer::new(TestStruct { value: 42 });
462
463 let guard = container.read().unwrap();
465 assert_eq!(guard.value, 42);
466 }
467
468 #[test]
469 fn test_wasm_write_access() {
470 let container = SharedContainer::new(TestStruct { value: 42 });
471
472 {
474 let mut guard = container.write().unwrap();
475 guard.value = 100;
476 }
477
478 let guard = container.read().unwrap();
480 assert_eq!(guard.value, 100);
481 }
482
483 #[test]
484 fn test_wasm_borrow_conflict() {
485 let container = SharedContainer::new(TestStruct { value: 42 });
486
487 let _guard = container.read().unwrap();
489
490 assert!(container.write().is_none());
492 }
493
494 #[test]
495 fn test_wasm_multiple_reads() {
496 let container = SharedContainer::new(TestStruct { value: 42 });
497
498 let _guard1 = container.read().unwrap();
500 let guard2 = container.read().unwrap();
501
502 assert_eq!(guard2.value, 42);
503 }
504
505 #[test]
506 fn test_wasm_weak_ref() {
507 let container = SharedContainer::new(TestStruct { value: 42 });
508 let weak = container.downgrade();
509
510 let container2 = weak.upgrade().unwrap();
512 assert_eq!(container2.read().unwrap().value, 42);
513
514 drop(container);
516 drop(container2);
517 assert!(weak.upgrade().is_none());
518 }
519}