1use std::fmt::Debug;
47use std::ops::{Deref, DerefMut};
48
49#[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
51use std::sync::{Arc, RwLock, Weak};
52
53#[cfg(feature = "tokio-sync")]
55use std::sync::{Arc, Weak};
56#[cfg(feature = "tokio-sync")]
57use tokio::sync::RwLock;
58
59#[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
61use std::cell::{Ref, RefCell, RefMut};
62#[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
63use std::rc::{Rc, Weak};
64
65
66#[derive(Debug)]
76pub struct SharedContainer<T: Debug> {
77 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
79 inner: Arc<RwLock<T>>,
80
81 #[cfg(feature = "tokio-sync")]
83 inner: Arc<RwLock<T>>,
84
85 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
87 inner: Rc<RefCell<T>>,
88}
89
90#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
92unsafe impl<T: Debug + Send> Send for SharedContainer<T> {}
93
94#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
95unsafe impl<T: Debug + Send + Sync> Sync for SharedContainer<T> {}
96
97#[derive(Debug)]
107pub struct WeakSharedContainer<T: Debug> {
108 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
110 inner: Weak<RwLock<T>>,
111
112 #[cfg(feature = "tokio-sync")]
114 inner: Weak<RwLock<T>>,
115
116 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
118 inner: Weak<RefCell<T>>,
119}
120
121impl<T: Debug> Clone for WeakSharedContainer<T> {
122 fn clone(&self) -> Self {
123 WeakSharedContainer {
125 inner: self.inner.clone(),
126 }
127 }
128}
129
130impl<T: Debug + PartialEq> PartialEq for SharedContainer<T> {
131 fn eq(&self, other: &Self) -> bool {
132 #[cfg(feature = "tokio-sync")]
133 {
134 use std::sync::Arc;
136 let self_inner = Arc::clone(&self.inner);
137 let other_inner = Arc::clone(&other.inner);
138
139 tokio::task::block_in_place(|| {
140 tokio::runtime::Handle::current().block_on(async {
141 let self_val = self_inner.read().await;
142 let other_val = other_inner.read().await;
143 *self_val == *other_val
144 })
145 })
146 }
147
148 #[cfg(not(feature = "tokio-sync"))]
149 {
150 match (self.read(), other.read()) {
151 (Some(self_val), Some(other_val)) => *self_val == *other_val,
152 _ => false,
153 }
154 }
155 }
156}
157
158impl<T: Debug> Clone for SharedContainer<T> {
159 fn clone(&self) -> Self {
160 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
161 {
162 SharedContainer {
163 inner: Arc::clone(&self.inner),
164 }
165 }
166
167 #[cfg(feature = "tokio-sync")]
168 {
169 SharedContainer {
170 inner: Arc::clone(&self.inner),
171 }
172 }
173
174 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
175 {
176 SharedContainer {
177 inner: Rc::clone(&self.inner),
178 }
179 }
180 }
181}
182
183impl<T: Debug + Clone> SharedContainer<T> {
184 pub fn get_cloned(&self) -> Option<T> {
197 #[cfg(feature = "tokio-sync")]
198 {
199 use std::sync::Arc;
203 let inner = Arc::clone(&self.inner);
204 let value = tokio::task::block_in_place(|| {
205 tokio::runtime::Handle::current().block_on(async {
206 let guard = inner.read().await;
207 (*guard).clone()
208 })
209 });
210 Some(value)
211 }
212
213 #[cfg(not(feature = "tokio-sync"))]
214 {
215 let guard = self.read()?;
216 Some((*guard).clone())
217 }
218 }
219
220 #[cfg(feature = "tokio-sync")]
239 pub async fn get_cloned_async(&self) -> T
240 where
241 T: Clone,
242 {
243 let guard = self.inner.read().await;
244 (*guard).clone()
245 }
246}
247
248impl<T: Debug> SharedContainer<T> {
249 pub fn new(value: T) -> Self {
257 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
258 {
259 SharedContainer {
260 inner: Arc::new(RwLock::new(value)),
261 }
262 }
263
264 #[cfg(feature = "tokio-sync")]
265 {
266 SharedContainer {
267 inner: Arc::new(RwLock::new(value)),
268 }
269 }
270
271 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
272 {
273 SharedContainer {
274 inner: Rc::new(RefCell::new(value)),
275 }
276 }
277 }
278
279 pub fn read(&self) -> Option<SharedReadGuard<T>> {
289 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
290 {
291 match self.inner.read() {
292 Ok(guard) => Some(SharedReadGuard::StdSync(guard)),
293 Err(_) => None,
294 }
295 }
296
297 #[cfg(feature = "tokio-sync")]
298 {
299 None
302 }
303
304 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
305 {
306 match self.inner.try_borrow() {
307 Ok(borrow) => Some(SharedReadGuard::Single(borrow)),
308 Err(_) => None,
309 }
310 }
311 }
312
313 pub fn write(&self) -> Option<SharedWriteGuard<T>> {
323 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
324 {
325 match self.inner.write() {
326 Ok(guard) => Some(SharedWriteGuard::StdSync(guard)),
327 Err(_) => None,
328 }
329 }
330
331 #[cfg(feature = "tokio-sync")]
332 {
333 None
336 }
337
338 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
339 {
340 match self.inner.try_borrow_mut() {
341 Ok(borrow) => Some(SharedWriteGuard::Single(borrow)),
342 Err(_) => None,
343 }
344 }
345 }
346
347 pub fn downgrade(&self) -> WeakSharedContainer<T> {
355 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
356 {
357 WeakSharedContainer {
358 inner: Arc::downgrade(&self.inner),
359 }
360 }
361
362 #[cfg(feature = "tokio-sync")]
363 {
364 WeakSharedContainer {
365 inner: Arc::downgrade(&self.inner),
366 }
367 }
368
369 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
370 {
371 WeakSharedContainer {
372 inner: Rc::downgrade(&self.inner),
373 }
374 }
375 }
376
377 #[cfg(feature = "tokio-sync")]
396 pub async fn read_async(&self) -> SharedReadGuard<'_, T> {
397 let guard = self.inner.read().await;
398 SharedReadGuard::TokioSync(guard)
399 }
400
401 #[cfg(feature = "tokio-sync")]
420 pub async fn write_async(&self) -> SharedWriteGuard<'_, T> {
421 let guard = self.inner.write().await;
422 SharedWriteGuard::TokioSync(guard)
423 }
424}
425
426impl<T: Debug> WeakSharedContainer<T> {
427 pub fn upgrade(&self) -> Option<SharedContainer<T>> {
436 self.inner.upgrade().map(|inner| SharedContainer { inner })
438 }
439}
440pub enum SharedReadGuard<'a, T: Debug> {
449 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
450 StdSync(std::sync::RwLockReadGuard<'a, T>),
451
452 #[cfg(feature = "tokio-sync")]
453 TokioSync(tokio::sync::RwLockReadGuard<'a, T>),
454
455 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
456 Single(Ref<'a, T>),
457}
458
459impl<'a, T: Debug> Deref for SharedReadGuard<'a, T> {
460 type Target = T;
461
462 fn deref(&self) -> &Self::Target {
463 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
464 {
465 match self {
466 SharedReadGuard::StdSync(guard) => guard.deref(),
467 #[allow(unreachable_patterns)]
468 _ => unreachable!(),
469 }
470 }
471
472 #[cfg(feature = "tokio-sync")]
473 {
474 match self {
475 SharedReadGuard::TokioSync(guard) => guard.deref(),
476 #[allow(unreachable_patterns)]
477 _ => unreachable!(),
478 }
479 }
480
481 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
482 {
483 match self {
484 SharedReadGuard::Single(borrow) => borrow.deref(),
485 #[allow(unreachable_patterns)]
486 _ => unreachable!(),
487 }
488 }
489 }
490}
491
492pub enum SharedWriteGuard<'a, T: Debug> {
501 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
502 StdSync(std::sync::RwLockWriteGuard<'a, T>),
503
504 #[cfg(feature = "tokio-sync")]
505 TokioSync(tokio::sync::RwLockWriteGuard<'a, T>),
506
507 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
508 Single(RefMut<'a, T>),
509}
510
511impl<'a, T: Debug> Deref for SharedWriteGuard<'a, T> {
512 type Target = T;
513
514 fn deref(&self) -> &Self::Target {
515 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
516 {
517 match self {
518 SharedWriteGuard::StdSync(guard) => guard.deref(),
519 #[allow(unreachable_patterns)]
520 _ => unreachable!(),
521 }
522 }
523
524 #[cfg(feature = "tokio-sync")]
525 {
526 match self {
527 SharedWriteGuard::TokioSync(guard) => guard.deref(),
528 #[allow(unreachable_patterns)]
529 _ => unreachable!(),
530 }
531 }
532
533 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
534 {
535 match self {
536 SharedWriteGuard::Single(borrow) => borrow.deref(),
537 #[allow(unreachable_patterns)]
538 _ => unreachable!(),
539 }
540 }
541 }
542}
543
544impl<'a, T: Debug> DerefMut for SharedWriteGuard<'a, T> {
545 fn deref_mut(&mut self) -> &mut Self::Target {
546 #[cfg(all(feature = "std-sync", not(feature = "tokio-sync"), not(feature = "wasm-sync")))]
547 {
548 match self {
549 SharedWriteGuard::StdSync(guard) => guard.deref_mut(),
550 #[allow(unreachable_patterns)]
551 _ => unreachable!(),
552 }
553 }
554
555 #[cfg(feature = "tokio-sync")]
556 {
557 match self {
558 SharedWriteGuard::TokioSync(guard) => guard.deref_mut(),
559 #[allow(unreachable_patterns)]
560 _ => unreachable!(),
561 }
562 }
563
564 #[cfg(any(feature = "wasm-sync", all(target_arch = "wasm32", not(feature = "std-sync"), not(feature = "tokio-sync"))))]
565 {
566 match self {
567 SharedWriteGuard::Single(borrow) => borrow.deref_mut(),
568 #[allow(unreachable_patterns)]
569 _ => unreachable!(),
570 }
571 }
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578
579 #[derive(Debug, Clone, PartialEq)]
580 #[allow(dead_code)]
581 struct TestStruct {
582 value: i32,
583 }
584
585 #[cfg(not(feature = "tokio-sync"))]
587 mod sync_tests {
588 use super::*;
589
590 #[test]
591 fn test_read_access() {
592 let container = SharedContainer::new(TestStruct { value: 42 });
593
594 let guard = container.read().unwrap();
596 assert_eq!(guard.value, 42);
597 }
598
599 #[test]
600 fn test_write_access() {
601 let container = SharedContainer::new(TestStruct { value: 42 });
602
603 {
605 let mut guard = container.write().unwrap();
606 guard.value = 100;
607 }
608
609 let guard = container.read().unwrap();
611 assert_eq!(guard.value, 100);
612 }
613
614 #[test]
615 fn test_clone_container() {
616 let container1 = SharedContainer::new(TestStruct { value: 42 });
617 let container2 = container1.clone();
618
619 {
621 let mut guard = container2.write().unwrap();
622 guard.value = 100;
623 }
624
625 let guard = container1.read().unwrap();
627 assert_eq!(guard.value, 100);
628 }
629
630 #[test]
631 fn test_get_cloned() {
632 let container = SharedContainer::new(TestStruct { value: 42 });
633 let cloned = container.get_cloned().unwrap();
634 assert_eq!(cloned, TestStruct { value: 42 });
635
636 {
638 let mut guard = container.write().unwrap();
639 guard.value = 100;
640 }
641
642 assert_eq!(cloned, TestStruct { value: 42 });
644
645 let new_clone = container.get_cloned().unwrap();
647 assert_eq!(new_clone, TestStruct { value: 100 });
648 }
649
650 #[test]
651 fn test_weak_ref() {
652 let container = SharedContainer::new(TestStruct { value: 42 });
653
654 let weak = container.downgrade();
656
657 let container2 = weak.upgrade().unwrap();
659
660 {
662 let mut guard = container2.write().unwrap();
663 guard.value = 100;
664 }
665
666 {
668 let guard = container.read().unwrap();
669 assert_eq!(guard.value, 100);
670 }
671 drop(container);
673 drop(container2);
674
675 assert!(weak.upgrade().is_none());
677 }
678
679 #[test]
680 fn test_weak_clone() {
681 let container = SharedContainer::new(TestStruct { value: 42 });
682
683 let weak1 = container.downgrade();
685 let weak2 = weak1.clone();
686
687 let container1 = weak1.upgrade().unwrap();
689 let container2 = weak2.upgrade().unwrap();
690
691 {
693 let mut guard = container2.write().unwrap();
694 guard.value = 100;
695 }
696
697 {
699 let guard = container1.read().unwrap();
700 assert_eq!(guard.value, 100);
701 }
702
703 drop(container);
705 drop(container1);
706 drop(container2);
707
708 assert!(weak1.upgrade().is_none());
710 assert!(weak2.upgrade().is_none());
711 }
712 }
713}
714
715#[cfg(test)]
717#[cfg(feature = "tokio-sync")]
718mod tokio_tests {
719 use super::*;
720 use tokio::runtime::Runtime;
721
722 #[derive(Debug, Clone, PartialEq)]
723 struct TestStruct {
724 value: i32,
725 }
726
727 #[test]
728 fn test_tokio_read_access() {
729 let rt = Runtime::new().unwrap();
730 rt.block_on(async {
731 let container = SharedContainer::new(TestStruct { value: 42 });
732
733 assert!(container.read().is_none());
735
736 let guard = container.read_async().await;
738 assert_eq!(guard.value, 42);
739 });
740 }
741
742 #[test]
743 fn test_tokio_write_access() {
744 let rt = Runtime::new().unwrap();
745 rt.block_on(async {
746 let container = SharedContainer::new(TestStruct { value: 42 });
747
748 assert!(container.write().is_none());
750
751 {
753 let mut guard = container.write_async().await;
754 guard.value = 100;
755 }
756
757 let guard = container.read_async().await;
759 assert_eq!(guard.value, 100);
760 });
761 }
762
763 #[test]
764 fn test_tokio_clone_container() {
765 let rt = Runtime::new().unwrap();
766 rt.block_on(async {
767 let container1 = SharedContainer::new(TestStruct { value: 42 });
768 let container2 = container1.clone();
769
770 {
772 let mut guard = container2.write_async().await;
773 guard.value = 100;
774 }
775
776 let guard = container1.read_async().await;
778 assert_eq!(guard.value, 100);
779 });
780 }
781
782 #[test]
783 fn test_tokio_weak_ref() {
784 let rt = Runtime::new().unwrap();
785 rt.block_on(async {
786 let container = SharedContainer::new(TestStruct { value: 42 });
787
788 let weak = container.downgrade();
790
791 let container2 = weak.upgrade().unwrap();
793
794 {
796 let mut guard = container2.write_async().await;
797 guard.value = 100;
798 }
799
800 {
802 let guard = container.read_async().await;
803 assert_eq!(guard.value, 100);
804 }
805
806 drop(container);
808 drop(container2);
809
810 assert!(weak.upgrade().is_none());
812 });
813 }
814}
815
816#[cfg(test)]
819#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
820mod wasm_tests {
821 use super::*;
822
823 #[derive(Debug, Clone, PartialEq)]
824 struct TestStruct {
825 value: i32,
826 }
827
828 #[test]
829 fn test_wasm_read_access() {
830 let container = SharedContainer::new(TestStruct { value: 42 });
831
832 let guard = container.read().unwrap();
834 assert_eq!(guard.value, 42);
835 }
836
837 #[test]
838 fn test_wasm_write_access() {
839 let container = SharedContainer::new(TestStruct { value: 42 });
840
841 {
843 let mut guard = container.write().unwrap();
844 guard.value = 100;
845 }
846
847 let guard = container.read().unwrap();
849 assert_eq!(guard.value, 100);
850 }
851
852 #[test]
853 fn test_wasm_borrow_conflict() {
854 let container = SharedContainer::new(TestStruct { value: 42 });
855
856 let _guard = container.read().unwrap();
858
859 assert!(container.write().is_none());
861 }
862
863 #[test]
864 fn test_wasm_multiple_reads() {
865 let container = SharedContainer::new(TestStruct { value: 42 });
866
867 let _guard1 = container.read().unwrap();
869 let guard2 = container.read().unwrap();
870
871 assert_eq!(guard2.value, 42);
872 }
873
874 #[test]
875 fn test_wasm_weak_ref() {
876 let container = SharedContainer::new(TestStruct { value: 42 });
877 let weak = container.downgrade();
878
879 let container2 = weak.upgrade().unwrap();
881 assert_eq!(container2.read().unwrap().value, 42);
882
883 drop(container);
885 drop(container2);
886 assert!(weak.upgrade().is_none());
887 }
888}