1#![cfg_attr(docsrs, feature(doc_cfg))]
91
92use std::ops::{Deref, DerefMut};
93
94#[cfg(all(
96 feature = "std-sync",
97 not(feature = "tokio-sync"),
98 not(feature = "wasm-sync")
99))]
100use std::sync::{Arc, RwLock, Weak};
101
102#[cfg(feature = "tokio-sync")]
104use std::sync::{Arc, Weak};
105#[cfg(feature = "tokio-sync")]
106use tokio::sync::RwLock;
107
108#[cfg(any(
110 feature = "wasm-sync",
111 all(
112 target_arch = "wasm32",
113 not(feature = "std-sync"),
114 not(feature = "tokio-sync")
115 )
116))]
117use std::cell::{Ref, RefCell, RefMut};
118#[cfg(any(
119 feature = "wasm-sync",
120 all(
121 target_arch = "wasm32",
122 not(feature = "std-sync"),
123 not(feature = "tokio-sync")
124 )
125))]
126use std::rc::{Rc, Weak as RcWeak};
127
128#[deprecated(
164 since = "0.3.0",
165 note = "Use `Shared<T>` for sync or `AsyncShared<T>` for async instead. See migration guide in docs."
166)]
167#[derive(Debug)]
168pub struct SharedContainer<T> {
169 #[cfg(all(
171 feature = "std-sync",
172 not(feature = "tokio-sync"),
173 not(feature = "wasm-sync")
174 ))]
175 std_inner: Arc<RwLock<T>>,
176
177 #[cfg(feature = "tokio-sync")]
179 tokio_inner: Arc<RwLock<T>>,
180
181 #[cfg(any(
183 feature = "wasm-sync",
184 all(
185 target_arch = "wasm32",
186 not(feature = "std-sync"),
187 not(feature = "tokio-sync")
188 )
189 ))]
190 wasm_inner: Rc<RefCell<T>>,
191}
192
193#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
195unsafe impl<T: Send> Send for SharedContainer<T> {}
196
197#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
198unsafe impl<T: Send + Sync> Sync for SharedContainer<T> {}
199
200#[deprecated(
213 since = "0.3.0",
214 note = "Use `WeakShared<T>` for sync or `WeakAsyncShared<T>` for async instead."
215)]
216#[derive(Debug)]
217pub struct WeakSharedContainer<T> {
218 #[cfg(all(
220 feature = "std-sync",
221 not(feature = "tokio-sync"),
222 not(feature = "wasm-sync")
223 ))]
224 std_inner: Weak<RwLock<T>>,
225
226 #[cfg(feature = "tokio-sync")]
228 tokio_inner: Weak<RwLock<T>>,
229
230 #[cfg(any(
232 feature = "wasm-sync",
233 all(
234 target_arch = "wasm32",
235 not(feature = "std-sync"),
236 not(feature = "tokio-sync")
237 )
238 ))]
239 wasm_inner: RcWeak<RefCell<T>>,
240}
241
242impl<T> Clone for WeakSharedContainer<T> {
243 fn clone(&self) -> Self {
244 #[cfg(all(
246 feature = "std-sync",
247 not(feature = "tokio-sync"),
248 not(feature = "wasm-sync")
249 ))]
250 {
251 WeakSharedContainer {
252 std_inner: self.std_inner.clone(),
253 }
254 }
255
256 #[cfg(feature = "tokio-sync")]
257 {
258 WeakSharedContainer {
259 tokio_inner: self.tokio_inner.clone(),
260 }
261 }
262
263 #[cfg(any(
264 feature = "wasm-sync",
265 all(
266 target_arch = "wasm32",
267 not(feature = "std-sync"),
268 not(feature = "tokio-sync")
269 )
270 ))]
271 {
272 WeakSharedContainer {
273 wasm_inner: self.wasm_inner.clone(),
274 }
275 }
276 }
277}
278
279impl<T: PartialEq> PartialEq for SharedContainer<T> {
280 fn eq(&self, _other: &Self) -> bool {
281 #[cfg(feature = "tokio-sync")]
282 {
283 false
287 }
288
289 #[cfg(not(feature = "tokio-sync"))]
290 {
291 match (self.read(), _other.read()) {
292 (Some(self_val), Some(other_val)) => *self_val == *other_val,
293 _ => false,
294 }
295 }
296 }
297}
298
299impl<T> Clone for SharedContainer<T> {
300 fn clone(&self) -> Self {
301 #[cfg(all(
302 feature = "std-sync",
303 not(feature = "tokio-sync"),
304 not(feature = "wasm-sync")
305 ))]
306 {
307 SharedContainer {
308 std_inner: Arc::clone(&self.std_inner),
309 }
310 }
311
312 #[cfg(feature = "tokio-sync")]
313 {
314 SharedContainer {
315 tokio_inner: Arc::clone(&self.tokio_inner),
316 }
317 }
318
319 #[cfg(any(
320 feature = "wasm-sync",
321 all(
322 target_arch = "wasm32",
323 not(feature = "std-sync"),
324 not(feature = "tokio-sync")
325 )
326 ))]
327 {
328 SharedContainer {
329 wasm_inner: Rc::clone(&self.wasm_inner),
330 }
331 }
332 }
333}
334
335impl<T: Clone> SharedContainer<T> {
336 #[cfg_attr(
349 feature = "tokio-sync",
350 doc = "WARNING: This method uses blocking operations when using tokio-sync feature, which is not ideal for async code. Consider using get_cloned_async() instead."
351 )]
352 pub fn get_cloned(&self) -> Option<T> {
353 #[cfg(feature = "tokio-sync")]
354 {
355 None
358 }
359
360 #[cfg(not(feature = "tokio-sync"))]
361 {
362 let guard = self.read()?;
363 Some((*guard).clone())
364 }
365 }
366
367 #[cfg(feature = "tokio-sync")]
386 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
387 pub async fn get_cloned_async(&self) -> T
388 where
389 T: Clone,
390 {
391 let guard = self.tokio_inner.read().await;
392 (*guard).clone()
393 }
394}
395
396impl<T> SharedContainer<T> {
397 pub fn new(value: T) -> Self {
405 #[cfg(all(
406 feature = "std-sync",
407 not(feature = "tokio-sync"),
408 not(feature = "wasm-sync")
409 ))]
410 {
411 SharedContainer {
412 std_inner: Arc::new(RwLock::new(value)),
413 }
414 }
415
416 #[cfg(feature = "tokio-sync")]
417 {
418 SharedContainer {
419 tokio_inner: Arc::new(RwLock::new(value)),
420 }
421 }
422
423 #[cfg(any(
424 feature = "wasm-sync",
425 all(
426 target_arch = "wasm32",
427 not(feature = "std-sync"),
428 not(feature = "tokio-sync")
429 )
430 ))]
431 {
432 SharedContainer {
433 wasm_inner: Rc::new(RefCell::new(value)),
434 }
435 }
436 }
437
438 #[cfg_attr(
448 feature = "tokio-sync",
449 doc = "WARNING: This method always returns None when using tokio-sync feature. Use read_async() instead."
450 )]
451 pub fn read(&self) -> Option<SharedReadGuard<'_, T>> {
452 #[cfg(feature = "tokio-sync")]
453 {
454 return None;
457 }
458
459 #[cfg(all(
460 feature = "std-sync",
461 not(feature = "tokio-sync"),
462 not(feature = "wasm-sync")
463 ))]
464 {
465 match self.std_inner.read() {
466 Ok(guard) => Some(SharedReadGuard::StdSync(guard)),
467 Err(_) => None,
468 }
469 }
470
471 #[cfg(any(
472 feature = "wasm-sync",
473 all(
474 target_arch = "wasm32",
475 not(feature = "std-sync"),
476 not(feature = "tokio-sync")
477 )
478 ))]
479 {
480 match self.wasm_inner.try_borrow() {
481 Ok(borrow) => Some(SharedReadGuard::Single(borrow)),
482 Err(_) => None,
483 }
484 }
485 }
486
487 #[cfg_attr(
497 feature = "tokio-sync",
498 doc = "WARNING: This method always returns None when using tokio-sync feature. Use write_async() instead."
499 )]
500 pub fn write(&self) -> Option<SharedWriteGuard<'_, T>> {
501 #[cfg(feature = "tokio-sync")]
502 {
503 return None;
506 }
507
508 #[cfg(all(
509 feature = "std-sync",
510 not(feature = "tokio-sync"),
511 not(feature = "wasm-sync")
512 ))]
513 {
514 match self.std_inner.write() {
515 Ok(guard) => Some(SharedWriteGuard::StdSync(guard)),
516 Err(_) => None,
517 }
518 }
519
520 #[cfg(any(
521 feature = "wasm-sync",
522 all(
523 target_arch = "wasm32",
524 not(feature = "std-sync"),
525 not(feature = "tokio-sync")
526 )
527 ))]
528 {
529 match self.wasm_inner.try_borrow_mut() {
530 Ok(borrow) => Some(SharedWriteGuard::Single(borrow)),
531 Err(_) => None,
532 }
533 }
534 }
535
536 pub fn downgrade(&self) -> WeakSharedContainer<T> {
544 #[cfg(all(
545 feature = "std-sync",
546 not(feature = "tokio-sync"),
547 not(feature = "wasm-sync")
548 ))]
549 {
550 WeakSharedContainer {
551 std_inner: Arc::downgrade(&self.std_inner),
552 }
553 }
554
555 #[cfg(feature = "tokio-sync")]
556 {
557 WeakSharedContainer {
558 tokio_inner: Arc::downgrade(&self.tokio_inner),
559 }
560 }
561
562 #[cfg(any(
563 feature = "wasm-sync",
564 all(
565 target_arch = "wasm32",
566 not(feature = "std-sync"),
567 not(feature = "tokio-sync")
568 )
569 ))]
570 {
571 WeakSharedContainer {
572 wasm_inner: Rc::downgrade(&self.wasm_inner),
573 }
574 }
575 }
576
577 #[cfg(feature = "tokio-sync")]
596 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
597 pub async fn read_async(&self) -> SharedReadGuard<'_, T> {
598 let guard = self.tokio_inner.read().await;
599 SharedReadGuard::TokioSync(guard)
600 }
601
602 #[cfg(feature = "tokio-sync")]
621 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
622 pub async fn write_async(&self) -> SharedWriteGuard<'_, T> {
623 let guard = self.tokio_inner.write().await;
624 SharedWriteGuard::TokioSync(guard)
625 }
626}
627
628impl<T> WeakSharedContainer<T> {
629 pub fn upgrade(&self) -> Option<SharedContainer<T>> {
638 #[cfg(all(
640 feature = "std-sync",
641 not(feature = "tokio-sync"),
642 not(feature = "wasm-sync")
643 ))]
644 {
645 self.std_inner
646 .upgrade()
647 .map(|inner| SharedContainer { std_inner: inner })
648 }
649
650 #[cfg(feature = "tokio-sync")]
651 {
652 self.tokio_inner
653 .upgrade()
654 .map(|inner| SharedContainer { tokio_inner: inner })
655 }
656
657 #[cfg(any(
658 feature = "wasm-sync",
659 all(
660 target_arch = "wasm32",
661 not(feature = "std-sync"),
662 not(feature = "tokio-sync")
663 )
664 ))]
665 {
666 self.wasm_inner
667 .upgrade()
668 .map(|inner| SharedContainer { wasm_inner: inner })
669 }
670 }
671}
672pub enum SharedReadGuard<'a, T> {
681 #[cfg(all(
682 feature = "std-sync",
683 not(feature = "tokio-sync"),
684 not(feature = "wasm-sync")
685 ))]
686 StdSync(std::sync::RwLockReadGuard<'a, T>),
687
688 #[cfg(feature = "tokio-sync")]
689 TokioSync(tokio::sync::RwLockReadGuard<'a, T>),
690
691 #[cfg(any(
692 feature = "wasm-sync",
693 all(
694 target_arch = "wasm32",
695 not(feature = "std-sync"),
696 not(feature = "tokio-sync")
697 )
698 ))]
699 Single(Ref<'a, T>),
700}
701
702impl<'a, T> Deref for SharedReadGuard<'a, T> {
703 type Target = T;
704
705 fn deref(&self) -> &Self::Target {
706 #[cfg(all(
707 feature = "std-sync",
708 not(feature = "tokio-sync"),
709 not(feature = "wasm-sync")
710 ))]
711 {
712 match self {
713 SharedReadGuard::StdSync(guard) => guard.deref(),
714 #[allow(unreachable_patterns)]
715 _ => unreachable!(),
716 }
717 }
718
719 #[cfg(feature = "tokio-sync")]
720 {
721 match self {
722 SharedReadGuard::TokioSync(guard) => guard.deref(),
723 #[allow(unreachable_patterns)]
724 _ => unreachable!(),
725 }
726 }
727
728 #[cfg(any(
729 feature = "wasm-sync",
730 all(
731 target_arch = "wasm32",
732 not(feature = "std-sync"),
733 not(feature = "tokio-sync")
734 )
735 ))]
736 {
737 match self {
738 SharedReadGuard::Single(borrow) => borrow.deref(),
739 #[allow(unreachable_patterns)]
740 _ => unreachable!(),
741 }
742 }
743 }
744}
745
746pub enum SharedWriteGuard<'a, T> {
755 #[cfg(all(
756 feature = "std-sync",
757 not(feature = "tokio-sync"),
758 not(feature = "wasm-sync")
759 ))]
760 StdSync(std::sync::RwLockWriteGuard<'a, T>),
761
762 #[cfg(feature = "tokio-sync")]
763 TokioSync(tokio::sync::RwLockWriteGuard<'a, T>),
764
765 #[cfg(any(
766 feature = "wasm-sync",
767 all(
768 target_arch = "wasm32",
769 not(feature = "std-sync"),
770 not(feature = "tokio-sync")
771 )
772 ))]
773 Single(RefMut<'a, T>),
774}
775
776impl<'a, T> Deref for SharedWriteGuard<'a, T> {
777 type Target = T;
778
779 fn deref(&self) -> &Self::Target {
780 #[cfg(all(
781 feature = "std-sync",
782 not(feature = "tokio-sync"),
783 not(feature = "wasm-sync")
784 ))]
785 {
786 match self {
787 SharedWriteGuard::StdSync(guard) => guard.deref(),
788 #[allow(unreachable_patterns)]
789 _ => unreachable!(),
790 }
791 }
792
793 #[cfg(feature = "tokio-sync")]
794 {
795 match self {
796 SharedWriteGuard::TokioSync(guard) => guard.deref(),
797 #[allow(unreachable_patterns)]
798 _ => unreachable!(),
799 }
800 }
801
802 #[cfg(any(
803 feature = "wasm-sync",
804 all(
805 target_arch = "wasm32",
806 not(feature = "std-sync"),
807 not(feature = "tokio-sync")
808 )
809 ))]
810 {
811 match self {
812 SharedWriteGuard::Single(borrow) => borrow.deref(),
813 #[allow(unreachable_patterns)]
814 _ => unreachable!(),
815 }
816 }
817 }
818}
819
820impl<'a, T> DerefMut for SharedWriteGuard<'a, T> {
821 fn deref_mut(&mut self) -> &mut Self::Target {
822 #[cfg(all(
823 feature = "std-sync",
824 not(feature = "tokio-sync"),
825 not(feature = "wasm-sync")
826 ))]
827 {
828 match self {
829 SharedWriteGuard::StdSync(guard) => guard.deref_mut(),
830 #[allow(unreachable_patterns)]
831 _ => unreachable!(),
832 }
833 }
834
835 #[cfg(feature = "tokio-sync")]
836 {
837 match self {
838 SharedWriteGuard::TokioSync(guard) => guard.deref_mut(),
839 #[allow(unreachable_patterns)]
840 _ => unreachable!(),
841 }
842 }
843
844 #[cfg(any(
845 feature = "wasm-sync",
846 all(
847 target_arch = "wasm32",
848 not(feature = "std-sync"),
849 not(feature = "tokio-sync")
850 )
851 ))]
852 {
853 match self {
854 SharedWriteGuard::Single(borrow) => borrow.deref_mut(),
855 #[allow(unreachable_patterns)]
856 _ => unreachable!(),
857 }
858 }
859 }
860}
861
862#[derive(Debug, Clone, PartialEq, Eq)]
868pub enum AccessError {
869 UnsupportedMode,
874
875 BorrowConflict,
880
881 Poisoned,
885}
886
887impl std::fmt::Display for AccessError {
888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
889 match self {
890 AccessError::UnsupportedMode => {
891 write!(f, "operation not supported for this container mode")
892 }
893 AccessError::BorrowConflict => {
894 write!(f, "borrow conflict: lock already held")
895 }
896 AccessError::Poisoned => {
897 write!(f, "lock poisoned by panic")
898 }
899 }
900 }
901}
902
903impl std::error::Error for AccessError {}
904
905pub trait SyncAccess<T> {
907 fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError>;
909
910 fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError>;
912
913 fn get_cloned(&self) -> Result<T, AccessError>
915 where
916 T: Clone;
917}
918
919#[cfg(feature = "async")]
921pub trait AsyncAccess<T> {
922 fn read_async<'a>(&'a self) -> impl std::future::Future<Output = AsyncReadGuard<'a, T>> + Send
924 where
925 T: 'a;
926
927 fn write_async<'a>(
929 &'a self,
930 ) -> impl std::future::Future<Output = AsyncWriteGuard<'a, T>> + Send
931 where
932 T: 'a;
933
934 fn get_cloned_async(&self) -> impl std::future::Future<Output = T> + Send
936 where
937 T: Clone;
938}
939
940#[derive(Debug)]
942pub enum SyncReadGuard<'a, T> {
943 #[cfg(not(target_arch = "wasm32"))]
944 Std(std::sync::RwLockReadGuard<'a, T>),
945 #[cfg(target_arch = "wasm32")]
946 Wasm(Ref<'a, T>),
947}
948
949impl<'a, T> Deref for SyncReadGuard<'a, T> {
950 type Target = T;
951
952 fn deref(&self) -> &Self::Target {
953 match self {
954 #[cfg(not(target_arch = "wasm32"))]
955 SyncReadGuard::Std(guard) => guard.deref(),
956 #[cfg(target_arch = "wasm32")]
957 SyncReadGuard::Wasm(guard) => guard.deref(),
958 }
959 }
960}
961
962#[derive(Debug)]
964pub enum SyncWriteGuard<'a, T> {
965 #[cfg(not(target_arch = "wasm32"))]
966 Std(std::sync::RwLockWriteGuard<'a, T>),
967 #[cfg(target_arch = "wasm32")]
968 Wasm(RefMut<'a, T>),
969}
970
971impl<'a, T> Deref for SyncWriteGuard<'a, T> {
972 type Target = T;
973
974 fn deref(&self) -> &Self::Target {
975 match self {
976 #[cfg(not(target_arch = "wasm32"))]
977 SyncWriteGuard::Std(guard) => guard.deref(),
978 #[cfg(target_arch = "wasm32")]
979 SyncWriteGuard::Wasm(guard) => guard.deref(),
980 }
981 }
982}
983
984impl<'a, T> DerefMut for SyncWriteGuard<'a, T> {
985 fn deref_mut(&mut self) -> &mut Self::Target {
986 match self {
987 #[cfg(not(target_arch = "wasm32"))]
988 SyncWriteGuard::Std(guard) => guard.deref_mut(),
989 #[cfg(target_arch = "wasm32")]
990 SyncWriteGuard::Wasm(guard) => guard.deref_mut(),
991 }
992 }
993}
994
995#[cfg(feature = "async")]
997#[derive(Debug)]
998pub struct AsyncReadGuard<'a, T>(tokio::sync::RwLockReadGuard<'a, T>);
999
1000#[cfg(feature = "async")]
1001impl<'a, T> Deref for AsyncReadGuard<'a, T> {
1002 type Target = T;
1003
1004 fn deref(&self) -> &Self::Target {
1005 self.0.deref()
1006 }
1007}
1008
1009#[cfg(feature = "async")]
1011#[derive(Debug)]
1012pub struct AsyncWriteGuard<'a, T>(tokio::sync::RwLockWriteGuard<'a, T>);
1013
1014#[cfg(feature = "async")]
1015impl<'a, T> Deref for AsyncWriteGuard<'a, T> {
1016 type Target = T;
1017
1018 fn deref(&self) -> &Self::Target {
1019 self.0.deref()
1020 }
1021}
1022
1023#[cfg(feature = "async")]
1024impl<'a, T> DerefMut for AsyncWriteGuard<'a, T> {
1025 fn deref_mut(&mut self) -> &mut Self::Target {
1026 self.0.deref_mut()
1027 }
1028}
1029
1030#[derive(Debug)]
1035pub struct Shared<T> {
1036 #[cfg(target_arch = "wasm32")]
1037 inner: Rc<RefCell<T>>,
1038
1039 #[cfg(not(target_arch = "wasm32"))]
1040 inner: std::sync::Arc<std::sync::RwLock<T>>,
1041}
1042
1043#[derive(Debug)]
1045pub struct WeakShared<T> {
1046 #[cfg(target_arch = "wasm32")]
1047 inner: RcWeak<RefCell<T>>,
1048
1049 #[cfg(not(target_arch = "wasm32"))]
1050 inner: std::sync::Weak<std::sync::RwLock<T>>,
1051}
1052
1053#[cfg(feature = "async")]
1057#[derive(Debug)]
1058pub struct AsyncShared<T> {
1059 inner: Arc<tokio::sync::RwLock<T>>,
1060}
1061
1062#[cfg(feature = "async")]
1063unsafe impl<T: Send> Send for AsyncShared<T> {}
1064
1065#[cfg(feature = "async")]
1066unsafe impl<T: Send + Sync> Sync for AsyncShared<T> {}
1067
1068#[cfg(feature = "async")]
1070#[derive(Debug)]
1071pub struct WeakAsyncShared<T> {
1072 inner: Weak<tokio::sync::RwLock<T>>,
1073}
1074
1075#[derive(Debug)]
1080pub enum SharedAny<T> {
1081 Sync(Shared<T>),
1082 #[cfg(feature = "async")]
1083 Async(AsyncShared<T>),
1084}
1085
1086#[derive(Debug)]
1088pub enum WeakSharedAny<T> {
1089 Sync(WeakShared<T>),
1090 #[cfg(feature = "async")]
1091 Async(WeakAsyncShared<T>),
1092}
1093
1094impl<T> Shared<T> {
1099 pub fn new(value: T) -> Self {
1101 #[cfg(target_arch = "wasm32")]
1102 {
1103 Shared {
1104 inner: Rc::new(RefCell::new(value)),
1105 }
1106 }
1107
1108 #[cfg(not(target_arch = "wasm32"))]
1109 {
1110 Shared {
1111 inner: std::sync::Arc::new(std::sync::RwLock::new(value)),
1112 }
1113 }
1114 }
1115
1116 pub fn downgrade(&self) -> WeakShared<T> {
1118 #[cfg(target_arch = "wasm32")]
1119 {
1120 WeakShared {
1121 inner: Rc::downgrade(&self.inner),
1122 }
1123 }
1124
1125 #[cfg(not(target_arch = "wasm32"))]
1126 {
1127 WeakShared {
1128 inner: std::sync::Arc::downgrade(&self.inner),
1129 }
1130 }
1131 }
1132}
1133
1134impl<T> Clone for Shared<T> {
1135 fn clone(&self) -> Self {
1136 #[cfg(target_arch = "wasm32")]
1137 {
1138 Shared {
1139 inner: Rc::clone(&self.inner),
1140 }
1141 }
1142
1143 #[cfg(not(target_arch = "wasm32"))]
1144 {
1145 Shared {
1146 inner: std::sync::Arc::clone(&self.inner),
1147 }
1148 }
1149 }
1150}
1151
1152impl<T> WeakShared<T> {
1153 pub fn upgrade(&self) -> Option<Shared<T>> {
1155 #[cfg(target_arch = "wasm32")]
1156 {
1157 self.inner.upgrade().map(|inner| Shared { inner })
1158 }
1159
1160 #[cfg(not(target_arch = "wasm32"))]
1161 {
1162 self.inner.upgrade().map(|inner| Shared { inner })
1163 }
1164 }
1165}
1166
1167impl<T> Clone for WeakShared<T> {
1168 fn clone(&self) -> Self {
1169 WeakShared {
1170 inner: self.inner.clone(),
1171 }
1172 }
1173}
1174
1175impl<T> SyncAccess<T> for Shared<T> {
1180 fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError> {
1181 #[cfg(not(target_arch = "wasm32"))]
1182 {
1183 self.inner
1184 .read()
1185 .map(SyncReadGuard::Std)
1186 .map_err(|_| AccessError::Poisoned)
1187 }
1188
1189 #[cfg(target_arch = "wasm32")]
1190 {
1191 self.inner
1192 .try_borrow()
1193 .map(SyncReadGuard::Wasm)
1194 .map_err(|_| AccessError::BorrowConflict)
1195 }
1196 }
1197
1198 fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError> {
1199 #[cfg(not(target_arch = "wasm32"))]
1200 {
1201 self.inner
1202 .write()
1203 .map(SyncWriteGuard::Std)
1204 .map_err(|_| AccessError::Poisoned)
1205 }
1206
1207 #[cfg(target_arch = "wasm32")]
1208 {
1209 self.inner
1210 .try_borrow_mut()
1211 .map(SyncWriteGuard::Wasm)
1212 .map_err(|_| AccessError::BorrowConflict)
1213 }
1214 }
1215
1216 fn get_cloned(&self) -> Result<T, AccessError>
1217 where
1218 T: Clone,
1219 {
1220 let guard = self.read()?;
1221 Ok((*guard).clone())
1222 }
1223}
1224
1225#[cfg(feature = "async")]
1226impl<T> AsyncShared<T> {
1227 pub fn new(value: T) -> Self {
1229 AsyncShared {
1230 inner: Arc::new(tokio::sync::RwLock::new(value)),
1231 }
1232 }
1233
1234 pub fn downgrade(&self) -> WeakAsyncShared<T> {
1236 WeakAsyncShared {
1237 inner: Arc::downgrade(&self.inner),
1238 }
1239 }
1240}
1241
1242#[cfg(feature = "async")]
1243impl<T> Clone for AsyncShared<T> {
1244 fn clone(&self) -> Self {
1245 AsyncShared {
1246 inner: Arc::clone(&self.inner),
1247 }
1248 }
1249}
1250
1251#[cfg(feature = "async")]
1252impl<T> WeakAsyncShared<T> {
1253 pub fn upgrade(&self) -> Option<AsyncShared<T>> {
1255 self.inner.upgrade().map(|inner| AsyncShared { inner })
1256 }
1257}
1258
1259#[cfg(feature = "async")]
1260impl<T> Clone for WeakAsyncShared<T> {
1261 fn clone(&self) -> Self {
1262 WeakAsyncShared {
1263 inner: self.inner.clone(),
1264 }
1265 }
1266}
1267
1268#[cfg(feature = "async")]
1273impl<T: Send + Sync> AsyncAccess<T> for AsyncShared<T> {
1274 async fn read_async<'a>(&'a self) -> AsyncReadGuard<'a, T>
1275 where
1276 T: 'a,
1277 {
1278 AsyncReadGuard(self.inner.read().await)
1279 }
1280
1281 async fn write_async<'a>(&'a self) -> AsyncWriteGuard<'a, T>
1282 where
1283 T: 'a,
1284 {
1285 AsyncWriteGuard(self.inner.write().await)
1286 }
1287
1288 async fn get_cloned_async(&self) -> T
1289 where
1290 T: Clone,
1291 {
1292 let guard = self.inner.read().await;
1293 (*guard).clone()
1294 }
1295}
1296
1297impl<T> From<Shared<T>> for SharedAny<T> {
1303 fn from(shared: Shared<T>) -> Self {
1304 SharedAny::Sync(shared)
1305 }
1306}
1307
1308#[cfg(feature = "async")]
1309impl<T> From<AsyncShared<T>> for SharedAny<T> {
1310 fn from(shared: AsyncShared<T>) -> Self {
1311 SharedAny::Async(shared)
1312 }
1313}
1314
1315impl<T> Clone for SharedAny<T> {
1316 fn clone(&self) -> Self {
1317 match self {
1318 SharedAny::Sync(s) => SharedAny::Sync(s.clone()),
1319 #[cfg(feature = "async")]
1320 SharedAny::Async(a) => SharedAny::Async(a.clone()),
1321 }
1322 }
1323}
1324
1325impl<T> SharedAny<T> {
1326 pub fn downgrade(&self) -> WeakSharedAny<T> {
1328 match self {
1329 SharedAny::Sync(s) => WeakSharedAny::Sync(s.downgrade()),
1330 #[cfg(feature = "async")]
1331 SharedAny::Async(a) => WeakSharedAny::Async(a.downgrade()),
1332 }
1333 }
1334}
1335
1336impl<T> WeakSharedAny<T> {
1337 pub fn upgrade(&self) -> Option<SharedAny<T>> {
1339 match self {
1340 WeakSharedAny::Sync(w) => w.upgrade().map(SharedAny::Sync),
1341 #[cfg(feature = "async")]
1342 WeakSharedAny::Async(w) => w.upgrade().map(SharedAny::Async),
1343 }
1344 }
1345}
1346
1347impl<T> Clone for WeakSharedAny<T> {
1348 fn clone(&self) -> Self {
1349 match self {
1350 WeakSharedAny::Sync(w) => WeakSharedAny::Sync(w.clone()),
1351 #[cfg(feature = "async")]
1352 WeakSharedAny::Async(w) => WeakSharedAny::Async(w.clone()),
1353 }
1354 }
1355}
1356
1357impl<T> SyncAccess<T> for SharedAny<T> {
1362 fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError> {
1363 match self {
1364 SharedAny::Sync(s) => s.read(),
1365 #[cfg(feature = "async")]
1366 SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1367 }
1368 }
1369
1370 fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError> {
1371 match self {
1372 SharedAny::Sync(s) => s.write(),
1373 #[cfg(feature = "async")]
1374 SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1375 }
1376 }
1377
1378 fn get_cloned(&self) -> Result<T, AccessError>
1379 where
1380 T: Clone,
1381 {
1382 match self {
1383 SharedAny::Sync(s) => s.get_cloned(),
1384 #[cfg(feature = "async")]
1385 SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1386 }
1387 }
1388}
1389
1390#[cfg(feature = "async")]
1391impl<T: Send + Sync> AsyncAccess<T> for SharedAny<T> {
1392 async fn read_async<'a>(&'a self) -> AsyncReadGuard<'a, T>
1393 where
1394 T: 'a,
1395 {
1396 match self {
1397 SharedAny::Async(a) => a.read_async().await,
1398 SharedAny::Sync(_) => {
1399 unreachable!("Cannot call async methods on sync container")
1403 }
1404 }
1405 }
1406
1407 async fn write_async<'a>(&'a self) -> AsyncWriteGuard<'a, T>
1408 where
1409 T: 'a,
1410 {
1411 match self {
1412 SharedAny::Async(a) => a.write_async().await,
1413 SharedAny::Sync(_) => {
1414 unreachable!("Cannot call async methods on sync container")
1415 }
1416 }
1417 }
1418
1419 async fn get_cloned_async(&self) -> T
1420 where
1421 T: Clone,
1422 {
1423 match self {
1424 SharedAny::Async(a) => a.get_cloned_async().await,
1425 SharedAny::Sync(_) => {
1426 unreachable!("Cannot call async methods on sync container")
1427 }
1428 }
1429 }
1430}
1431
1432#[cfg(test)]
1433mod tests {
1434
1435 #[derive(Debug, Clone, PartialEq)]
1436 #[allow(dead_code)]
1437 struct TestStruct {
1438 value: i32,
1439 }
1440
1441 #[cfg(not(feature = "tokio-sync"))]
1443 mod sync_tests {
1444 use super::*;
1445 use crate::SharedContainer;
1446
1447 #[test]
1448 fn test_read_access() {
1449 let container = SharedContainer::new(TestStruct { value: 42 });
1450
1451 let guard = container.read().unwrap();
1453 assert_eq!(guard.value, 42);
1454 }
1455
1456 #[test]
1457 fn test_write_access() {
1458 let container = SharedContainer::new(TestStruct { value: 42 });
1459
1460 {
1462 let mut guard = container.write().unwrap();
1463 guard.value = 100;
1464 }
1465
1466 let guard = container.read().unwrap();
1468 assert_eq!(guard.value, 100);
1469 }
1470
1471 #[test]
1472 fn test_clone_container() {
1473 let container1 = SharedContainer::new(TestStruct { value: 42 });
1474 let container2 = container1.clone();
1475
1476 {
1478 let mut guard = container2.write().unwrap();
1479 guard.value = 100;
1480 }
1481
1482 let guard = container1.read().unwrap();
1484 assert_eq!(guard.value, 100);
1485 }
1486
1487 #[test]
1488 fn test_get_cloned() {
1489 let container = SharedContainer::new(TestStruct { value: 42 });
1490 let cloned = container.get_cloned().unwrap();
1491 assert_eq!(cloned, TestStruct { value: 42 });
1492
1493 {
1495 let mut guard = container.write().unwrap();
1496 guard.value = 100;
1497 }
1498
1499 assert_eq!(cloned, TestStruct { value: 42 });
1501
1502 let new_clone = container.get_cloned().unwrap();
1504 assert_eq!(new_clone, TestStruct { value: 100 });
1505 }
1506
1507 #[test]
1508 fn test_weak_ref() {
1509 let container = SharedContainer::new(TestStruct { value: 42 });
1510
1511 let weak = container.downgrade();
1513
1514 let container2 = weak.upgrade().unwrap();
1516
1517 {
1519 let mut guard = container2.write().unwrap();
1520 guard.value = 100;
1521 }
1522
1523 {
1525 let guard = container.read().unwrap();
1526 assert_eq!(guard.value, 100);
1527 }
1528 drop(container);
1530 drop(container2);
1531
1532 assert!(weak.upgrade().is_none());
1534 }
1535
1536 #[test]
1537 fn test_weak_clone() {
1538 let container = SharedContainer::new(TestStruct { value: 42 });
1539
1540 let weak1 = container.downgrade();
1542 let weak2 = weak1.clone();
1543
1544 let container1 = weak1.upgrade().unwrap();
1546 let container2 = weak2.upgrade().unwrap();
1547
1548 {
1550 let mut guard = container2.write().unwrap();
1551 guard.value = 100;
1552 }
1553
1554 {
1556 let guard = container1.read().unwrap();
1557 assert_eq!(guard.value, 100);
1558 }
1559
1560 drop(container);
1562 drop(container1);
1563 drop(container2);
1564
1565 assert!(weak1.upgrade().is_none());
1567 assert!(weak2.upgrade().is_none());
1568 }
1569 }
1570}
1571
1572#[cfg(test)]
1574#[cfg(feature = "tokio-sync")]
1575mod tokio_tests {
1576 use super::*;
1577 use tokio::runtime::Runtime;
1578
1579 #[derive(Debug, Clone, PartialEq)]
1580 struct TestStruct {
1581 value: i32,
1582 }
1583
1584 #[test]
1585 fn test_tokio_read_access() {
1586 let rt = Runtime::new().unwrap();
1587 rt.block_on(async {
1588 let container = SharedContainer::new(TestStruct { value: 42 });
1589
1590 assert!(container.read().is_none());
1592
1593 let guard = container.read_async().await;
1595 assert_eq!(guard.value, 42);
1596 });
1597 }
1598
1599 #[test]
1600 fn test_tokio_write_access() {
1601 let rt = Runtime::new().unwrap();
1602 rt.block_on(async {
1603 let container = SharedContainer::new(TestStruct { value: 42 });
1604
1605 assert!(container.write().is_none());
1607
1608 {
1610 let mut guard = container.write_async().await;
1611 guard.value = 100;
1612 }
1613
1614 let guard = container.read_async().await;
1616 assert_eq!(guard.value, 100);
1617 });
1618 }
1619
1620 #[test]
1621 fn test_tokio_clone_container() {
1622 let rt = Runtime::new().unwrap();
1623 rt.block_on(async {
1624 let container1 = SharedContainer::new(TestStruct { value: 42 });
1625 let container2 = container1.clone();
1626
1627 {
1629 let mut guard = container2.write_async().await;
1630 guard.value = 100;
1631 }
1632
1633 let guard = container1.read_async().await;
1635 assert_eq!(guard.value, 100);
1636 });
1637 }
1638
1639 #[test]
1640 fn test_tokio_weak_ref() {
1641 let rt = Runtime::new().unwrap();
1642 rt.block_on(async {
1643 let container = SharedContainer::new(TestStruct { value: 42 });
1644
1645 let weak = container.downgrade();
1647
1648 let container2 = weak.upgrade().unwrap();
1650
1651 {
1653 let mut guard = container2.write_async().await;
1654 guard.value = 100;
1655 }
1656
1657 {
1659 let guard = container.read_async().await;
1660 assert_eq!(guard.value, 100);
1661 }
1662
1663 drop(container);
1665 drop(container2);
1666
1667 assert!(weak.upgrade().is_none());
1669 });
1670 }
1671}
1672
1673#[cfg(test)]
1676#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
1677mod wasm_tests {
1678 use super::*;
1679
1680 #[derive(Debug, Clone, PartialEq)]
1681 struct TestStruct {
1682 value: i32,
1683 }
1684
1685 #[test]
1686 fn test_wasm_read_access() {
1687 let container = SharedContainer::new(TestStruct { value: 42 });
1688
1689 let guard = container.read().unwrap();
1691 assert_eq!(guard.value, 42);
1692 }
1693
1694 #[test]
1695 fn test_wasm_write_access() {
1696 let container = SharedContainer::new(TestStruct { value: 42 });
1697
1698 {
1700 let mut guard = container.write().unwrap();
1701 guard.value = 100;
1702 }
1703
1704 let guard = container.read().unwrap();
1706 assert_eq!(guard.value, 100);
1707 }
1708
1709 #[test]
1710 fn test_wasm_borrow_conflict() {
1711 let container = SharedContainer::new(TestStruct { value: 42 });
1712
1713 let _guard = container.read().unwrap();
1715
1716 assert!(container.write().is_none());
1718 }
1719
1720 #[test]
1721 fn test_wasm_multiple_reads() {
1722 let container = SharedContainer::new(TestStruct { value: 42 });
1723
1724 let _guard1 = container.read().unwrap();
1726 let guard2 = container.read().unwrap();
1727
1728 assert_eq!(guard2.value, 42);
1729 }
1730
1731 #[test]
1732 fn test_wasm_weak_ref() {
1733 let container = SharedContainer::new(TestStruct { value: 42 });
1734 let weak = container.downgrade();
1735
1736 let container2 = weak.upgrade().unwrap();
1738 assert_eq!(container2.read().unwrap().value, 42);
1739
1740 drop(container);
1742 drop(container2);
1743 assert!(weak.upgrade().is_none());
1744 }
1745}