1#![cfg_attr(docsrs, feature(doc_cfg))]
47
48use std::ops::{Deref, DerefMut};
49
50#[cfg(feature = "tokio-sync")]
55#[doc(hidden)]
56macro_rules! tokio_sync_warning {
57 ($msg:expr) => {
58 #[doc(hidden)]
59 #[allow(deprecated)]
60 struct __TokioSyncWarning;
61
62 impl __TokioSyncWarning {
63 #[deprecated(note = $msg)]
64 #[doc(hidden)]
65 fn __warn() {}
66 }
67
68 let _ = __TokioSyncWarning::__warn();
70 };
71}
72
73#[cfg(all(
82 feature = "std-sync",
83 not(feature = "tokio-sync"),
84 not(feature = "wasm-sync")
85))]
86use std::sync::{Arc, RwLock, Weak};
87
88#[cfg(feature = "tokio-sync")]
90use std::sync::{Arc, Weak};
91#[cfg(feature = "tokio-sync")]
92use tokio::sync::RwLock;
93
94#[cfg(any(
96 feature = "wasm-sync",
97 all(
98 target_arch = "wasm32",
99 not(feature = "std-sync"),
100 not(feature = "tokio-sync")
101 )
102))]
103use std::cell::{Ref, RefCell, RefMut};
104#[cfg(any(
105 feature = "wasm-sync",
106 all(
107 target_arch = "wasm32",
108 not(feature = "std-sync"),
109 not(feature = "tokio-sync")
110 )
111))]
112use std::rc::{Rc, Weak as RcWeak};
113
114#[derive(Debug)]
124pub struct SharedContainer<T> {
125 #[cfg(all(
127 feature = "std-sync",
128 not(feature = "tokio-sync"),
129 not(feature = "wasm-sync")
130 ))]
131 std_inner: Arc<RwLock<T>>,
132
133 #[cfg(feature = "tokio-sync")]
135 tokio_inner: Arc<RwLock<T>>,
136
137 #[cfg(any(
139 feature = "wasm-sync",
140 all(
141 target_arch = "wasm32",
142 not(feature = "std-sync"),
143 not(feature = "tokio-sync")
144 )
145 ))]
146 wasm_inner: Rc<RefCell<T>>,
147}
148
149#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
151unsafe impl<T: Send> Send for SharedContainer<T> {}
152
153#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
154unsafe impl<T: Send + Sync> Sync for SharedContainer<T> {}
155
156#[derive(Debug)]
166pub struct WeakSharedContainer<T> {
167 #[cfg(all(
169 feature = "std-sync",
170 not(feature = "tokio-sync"),
171 not(feature = "wasm-sync")
172 ))]
173 std_inner: Weak<RwLock<T>>,
174
175 #[cfg(feature = "tokio-sync")]
177 tokio_inner: Weak<RwLock<T>>,
178
179 #[cfg(any(
181 feature = "wasm-sync",
182 all(
183 target_arch = "wasm32",
184 not(feature = "std-sync"),
185 not(feature = "tokio-sync")
186 )
187 ))]
188 wasm_inner: RcWeak<RefCell<T>>,
189}
190
191impl<T> Clone for WeakSharedContainer<T> {
192 fn clone(&self) -> Self {
193 #[cfg(all(
195 feature = "std-sync",
196 not(feature = "tokio-sync"),
197 not(feature = "wasm-sync")
198 ))]
199 {
200 WeakSharedContainer {
201 std_inner: self.std_inner.clone(),
202 }
203 }
204
205 #[cfg(feature = "tokio-sync")]
206 {
207 WeakSharedContainer {
208 tokio_inner: self.tokio_inner.clone(),
209 }
210 }
211
212 #[cfg(any(
213 feature = "wasm-sync",
214 all(
215 target_arch = "wasm32",
216 not(feature = "std-sync"),
217 not(feature = "tokio-sync")
218 )
219 ))]
220 {
221 WeakSharedContainer {
222 wasm_inner: self.wasm_inner.clone(),
223 }
224 }
225 }
226}
227
228impl<T: PartialEq> PartialEq for SharedContainer<T> {
229 fn eq(&self, other: &Self) -> bool {
230 #[cfg(feature = "tokio-sync")]
231 {
232 use std::sync::Arc;
234 let self_inner = Arc::clone(&self.tokio_inner);
235 let other_inner = Arc::clone(&other.tokio_inner);
236
237 tokio::task::block_in_place(|| {
238 let rt = tokio::runtime::Builder::new_current_thread()
240 .enable_all()
241 .build()
242 .unwrap();
243 rt.block_on(async {
244 let self_val = self_inner.read().await;
245 let other_val = other_inner.read().await;
246 *self_val == *other_val
247 })
248 })
249 }
250
251 #[cfg(not(feature = "tokio-sync"))]
252 {
253 match (self.read(), other.read()) {
254 (Some(self_val), Some(other_val)) => *self_val == *other_val,
255 _ => false,
256 }
257 }
258 }
259}
260
261impl<T> Clone for SharedContainer<T> {
262 fn clone(&self) -> Self {
263 #[cfg(all(
264 feature = "std-sync",
265 not(feature = "tokio-sync"),
266 not(feature = "wasm-sync")
267 ))]
268 {
269 SharedContainer {
270 std_inner: Arc::clone(&self.std_inner),
271 }
272 }
273
274 #[cfg(feature = "tokio-sync")]
275 {
276 SharedContainer {
277 tokio_inner: Arc::clone(&self.tokio_inner),
278 }
279 }
280
281 #[cfg(any(
282 feature = "wasm-sync",
283 all(
284 target_arch = "wasm32",
285 not(feature = "std-sync"),
286 not(feature = "tokio-sync")
287 )
288 ))]
289 {
290 SharedContainer {
291 wasm_inner: Rc::clone(&self.wasm_inner),
292 }
293 }
294 }
295}
296
297impl<T: Clone> SharedContainer<T> {
298 #[cfg_attr(
311 feature = "tokio-sync",
312 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."
313 )]
314 pub fn get_cloned(&self) -> Option<T> {
315 #[cfg(feature = "tokio-sync")]
316 {
317 tokio_sync_warning!(
318 "This method uses blocking operations when using tokio-sync feature, which is not ideal for async code. Consider using get_cloned_async() instead."
319 );
320 use std::sync::Arc;
324 let inner = Arc::clone(&self.tokio_inner);
325 let value = tokio::task::block_in_place(|| {
326 let rt = tokio::runtime::Builder::new_current_thread()
328 .enable_all()
329 .build()
330 .unwrap();
331 rt.block_on(async {
332 let guard = inner.read().await;
333 (*guard).clone()
334 })
335 });
336 Some(value)
337 }
338
339 #[cfg(not(feature = "tokio-sync"))]
340 {
341 let guard = self.read()?;
342 Some((*guard).clone())
343 }
344 }
345
346 #[cfg(feature = "tokio-sync")]
365 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
366 pub async fn get_cloned_async(&self) -> T
367 where
368 T: Clone,
369 {
370 let guard = self.tokio_inner.read().await;
371 (*guard).clone()
372 }
373}
374
375impl<T> SharedContainer<T> {
376 pub fn new(value: T) -> Self {
384 #[cfg(all(
385 feature = "std-sync",
386 not(feature = "tokio-sync"),
387 not(feature = "wasm-sync")
388 ))]
389 {
390 SharedContainer {
391 std_inner: Arc::new(RwLock::new(value)),
392 }
393 }
394
395 #[cfg(feature = "tokio-sync")]
396 {
397 SharedContainer {
398 tokio_inner: Arc::new(RwLock::new(value)),
399 }
400 }
401
402 #[cfg(any(
403 feature = "wasm-sync",
404 all(
405 target_arch = "wasm32",
406 not(feature = "std-sync"),
407 not(feature = "tokio-sync")
408 )
409 ))]
410 {
411 SharedContainer {
412 wasm_inner: Rc::new(RefCell::new(value)),
413 }
414 }
415 }
416
417 #[cfg_attr(
427 feature = "tokio-sync",
428 doc = "WARNING: This method always returns None when using tokio-sync feature. Use read_async() instead."
429 )]
430 pub fn read(&self) -> Option<SharedReadGuard<T>> {
431 #[cfg(feature = "tokio-sync")]
432 {
433 tokio_sync_warning!(
434 "This method always returns None when using tokio-sync feature. Use read_async() instead."
435 );
436 return None;
439 }
440
441 #[cfg(all(
442 feature = "std-sync",
443 not(feature = "tokio-sync"),
444 not(feature = "wasm-sync")
445 ))]
446 {
447 match self.std_inner.read() {
448 Ok(guard) => Some(SharedReadGuard::StdSync(guard)),
449 Err(_) => None,
450 }
451 }
452
453 #[cfg(any(
454 feature = "wasm-sync",
455 all(
456 target_arch = "wasm32",
457 not(feature = "std-sync"),
458 not(feature = "tokio-sync")
459 )
460 ))]
461 {
462 match self.wasm_inner.try_borrow() {
463 Ok(borrow) => Some(SharedReadGuard::Single(borrow)),
464 Err(_) => None,
465 }
466 }
467 }
468
469 #[cfg_attr(
479 feature = "tokio-sync",
480 doc = "WARNING: This method always returns None when using tokio-sync feature. Use write_async() instead."
481 )]
482 pub fn write(&self) -> Option<SharedWriteGuard<T>> {
483 #[cfg(feature = "tokio-sync")]
484 {
485 tokio_sync_warning!(
486 "This method always returns None when using tokio-sync feature. Use write_async() instead."
487 );
488 return None;
491 }
492
493 #[cfg(all(
494 feature = "std-sync",
495 not(feature = "tokio-sync"),
496 not(feature = "wasm-sync")
497 ))]
498 {
499 match self.std_inner.write() {
500 Ok(guard) => Some(SharedWriteGuard::StdSync(guard)),
501 Err(_) => None,
502 }
503 }
504
505 #[cfg(any(
506 feature = "wasm-sync",
507 all(
508 target_arch = "wasm32",
509 not(feature = "std-sync"),
510 not(feature = "tokio-sync")
511 )
512 ))]
513 {
514 match self.wasm_inner.try_borrow_mut() {
515 Ok(borrow) => Some(SharedWriteGuard::Single(borrow)),
516 Err(_) => None,
517 }
518 }
519 }
520
521 pub fn downgrade(&self) -> WeakSharedContainer<T> {
529 #[cfg(all(
530 feature = "std-sync",
531 not(feature = "tokio-sync"),
532 not(feature = "wasm-sync")
533 ))]
534 {
535 WeakSharedContainer {
536 std_inner: Arc::downgrade(&self.std_inner),
537 }
538 }
539
540 #[cfg(feature = "tokio-sync")]
541 {
542 WeakSharedContainer {
543 tokio_inner: Arc::downgrade(&self.tokio_inner),
544 }
545 }
546
547 #[cfg(any(
548 feature = "wasm-sync",
549 all(
550 target_arch = "wasm32",
551 not(feature = "std-sync"),
552 not(feature = "tokio-sync")
553 )
554 ))]
555 {
556 WeakSharedContainer {
557 wasm_inner: Rc::downgrade(&self.wasm_inner),
558 }
559 }
560 }
561
562 #[cfg(feature = "tokio-sync")]
581 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
582 pub async fn read_async(&self) -> SharedReadGuard<'_, T> {
583 let guard = self.tokio_inner.read().await;
584 SharedReadGuard::TokioSync(guard)
585 }
586
587 #[cfg(feature = "tokio-sync")]
606 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
607 pub async fn write_async(&self) -> SharedWriteGuard<'_, T> {
608 let guard = self.tokio_inner.write().await;
609 SharedWriteGuard::TokioSync(guard)
610 }
611}
612
613impl<T> WeakSharedContainer<T> {
614 pub fn upgrade(&self) -> Option<SharedContainer<T>> {
623 #[cfg(all(
625 feature = "std-sync",
626 not(feature = "tokio-sync"),
627 not(feature = "wasm-sync")
628 ))]
629 {
630 self.std_inner
631 .upgrade()
632 .map(|inner| SharedContainer { std_inner: inner })
633 }
634
635 #[cfg(feature = "tokio-sync")]
636 {
637 self.tokio_inner
638 .upgrade()
639 .map(|inner| SharedContainer { tokio_inner: inner })
640 }
641
642 #[cfg(any(
643 feature = "wasm-sync",
644 all(
645 target_arch = "wasm32",
646 not(feature = "std-sync"),
647 not(feature = "tokio-sync")
648 )
649 ))]
650 {
651 self.wasm_inner
652 .upgrade()
653 .map(|inner| SharedContainer { wasm_inner: inner })
654 }
655 }
656}
657pub enum SharedReadGuard<'a, T> {
666 #[cfg(all(
667 feature = "std-sync",
668 not(feature = "tokio-sync"),
669 not(feature = "wasm-sync")
670 ))]
671 StdSync(std::sync::RwLockReadGuard<'a, T>),
672
673 #[cfg(feature = "tokio-sync")]
674 TokioSync(tokio::sync::RwLockReadGuard<'a, T>),
675
676 #[cfg(any(
677 feature = "wasm-sync",
678 all(
679 target_arch = "wasm32",
680 not(feature = "std-sync"),
681 not(feature = "tokio-sync")
682 )
683 ))]
684 Single(Ref<'a, T>),
685}
686
687impl<'a, T> Deref for SharedReadGuard<'a, T> {
688 type Target = T;
689
690 fn deref(&self) -> &Self::Target {
691 #[cfg(all(
692 feature = "std-sync",
693 not(feature = "tokio-sync"),
694 not(feature = "wasm-sync")
695 ))]
696 {
697 match self {
698 SharedReadGuard::StdSync(guard) => guard.deref(),
699 #[allow(unreachable_patterns)]
700 _ => unreachable!(),
701 }
702 }
703
704 #[cfg(feature = "tokio-sync")]
705 {
706 match self {
707 SharedReadGuard::TokioSync(guard) => guard.deref(),
708 #[allow(unreachable_patterns)]
709 _ => unreachable!(),
710 }
711 }
712
713 #[cfg(any(
714 feature = "wasm-sync",
715 all(
716 target_arch = "wasm32",
717 not(feature = "std-sync"),
718 not(feature = "tokio-sync")
719 )
720 ))]
721 {
722 match self {
723 SharedReadGuard::Single(borrow) => borrow.deref(),
724 #[allow(unreachable_patterns)]
725 _ => unreachable!(),
726 }
727 }
728 }
729}
730
731pub enum SharedWriteGuard<'a, T> {
740 #[cfg(all(
741 feature = "std-sync",
742 not(feature = "tokio-sync"),
743 not(feature = "wasm-sync")
744 ))]
745 StdSync(std::sync::RwLockWriteGuard<'a, T>),
746
747 #[cfg(feature = "tokio-sync")]
748 TokioSync(tokio::sync::RwLockWriteGuard<'a, T>),
749
750 #[cfg(any(
751 feature = "wasm-sync",
752 all(
753 target_arch = "wasm32",
754 not(feature = "std-sync"),
755 not(feature = "tokio-sync")
756 )
757 ))]
758 Single(RefMut<'a, T>),
759}
760
761impl<'a, T> Deref for SharedWriteGuard<'a, T> {
762 type Target = T;
763
764 fn deref(&self) -> &Self::Target {
765 #[cfg(all(
766 feature = "std-sync",
767 not(feature = "tokio-sync"),
768 not(feature = "wasm-sync")
769 ))]
770 {
771 match self {
772 SharedWriteGuard::StdSync(guard) => guard.deref(),
773 #[allow(unreachable_patterns)]
774 _ => unreachable!(),
775 }
776 }
777
778 #[cfg(feature = "tokio-sync")]
779 {
780 match self {
781 SharedWriteGuard::TokioSync(guard) => guard.deref(),
782 #[allow(unreachable_patterns)]
783 _ => unreachable!(),
784 }
785 }
786
787 #[cfg(any(
788 feature = "wasm-sync",
789 all(
790 target_arch = "wasm32",
791 not(feature = "std-sync"),
792 not(feature = "tokio-sync")
793 )
794 ))]
795 {
796 match self {
797 SharedWriteGuard::Single(borrow) => borrow.deref(),
798 #[allow(unreachable_patterns)]
799 _ => unreachable!(),
800 }
801 }
802 }
803}
804
805impl<'a, T> DerefMut for SharedWriteGuard<'a, T> {
806 fn deref_mut(&mut self) -> &mut Self::Target {
807 #[cfg(all(
808 feature = "std-sync",
809 not(feature = "tokio-sync"),
810 not(feature = "wasm-sync")
811 ))]
812 {
813 match self {
814 SharedWriteGuard::StdSync(guard) => guard.deref_mut(),
815 #[allow(unreachable_patterns)]
816 _ => unreachable!(),
817 }
818 }
819
820 #[cfg(feature = "tokio-sync")]
821 {
822 match self {
823 SharedWriteGuard::TokioSync(guard) => guard.deref_mut(),
824 #[allow(unreachable_patterns)]
825 _ => unreachable!(),
826 }
827 }
828
829 #[cfg(any(
830 feature = "wasm-sync",
831 all(
832 target_arch = "wasm32",
833 not(feature = "std-sync"),
834 not(feature = "tokio-sync")
835 )
836 ))]
837 {
838 match self {
839 SharedWriteGuard::Single(borrow) => borrow.deref_mut(),
840 #[allow(unreachable_patterns)]
841 _ => unreachable!(),
842 }
843 }
844 }
845}
846
847#[cfg(test)]
848mod tests {
849
850 #[derive(Debug, Clone, PartialEq)]
851 #[allow(dead_code)]
852 struct TestStruct {
853 value: i32,
854 }
855
856 #[cfg(not(feature = "tokio-sync"))]
858 mod sync_tests {
859 use super::*;
860 use crate::SharedContainer;
861
862 #[test]
863 fn test_read_access() {
864 let container = SharedContainer::new(TestStruct { value: 42 });
865
866 let guard = container.read().unwrap();
868 assert_eq!(guard.value, 42);
869 }
870
871 #[test]
872 fn test_write_access() {
873 let container = SharedContainer::new(TestStruct { value: 42 });
874
875 {
877 let mut guard = container.write().unwrap();
878 guard.value = 100;
879 }
880
881 let guard = container.read().unwrap();
883 assert_eq!(guard.value, 100);
884 }
885
886 #[test]
887 fn test_clone_container() {
888 let container1 = SharedContainer::new(TestStruct { value: 42 });
889 let container2 = container1.clone();
890
891 {
893 let mut guard = container2.write().unwrap();
894 guard.value = 100;
895 }
896
897 let guard = container1.read().unwrap();
899 assert_eq!(guard.value, 100);
900 }
901
902 #[test]
903 fn test_get_cloned() {
904 let container = SharedContainer::new(TestStruct { value: 42 });
905 let cloned = container.get_cloned().unwrap();
906 assert_eq!(cloned, TestStruct { value: 42 });
907
908 {
910 let mut guard = container.write().unwrap();
911 guard.value = 100;
912 }
913
914 assert_eq!(cloned, TestStruct { value: 42 });
916
917 let new_clone = container.get_cloned().unwrap();
919 assert_eq!(new_clone, TestStruct { value: 100 });
920 }
921
922 #[test]
923 fn test_weak_ref() {
924 let container = SharedContainer::new(TestStruct { value: 42 });
925
926 let weak = container.downgrade();
928
929 let container2 = weak.upgrade().unwrap();
931
932 {
934 let mut guard = container2.write().unwrap();
935 guard.value = 100;
936 }
937
938 {
940 let guard = container.read().unwrap();
941 assert_eq!(guard.value, 100);
942 }
943 drop(container);
945 drop(container2);
946
947 assert!(weak.upgrade().is_none());
949 }
950
951 #[test]
952 fn test_weak_clone() {
953 let container = SharedContainer::new(TestStruct { value: 42 });
954
955 let weak1 = container.downgrade();
957 let weak2 = weak1.clone();
958
959 let container1 = weak1.upgrade().unwrap();
961 let container2 = weak2.upgrade().unwrap();
962
963 {
965 let mut guard = container2.write().unwrap();
966 guard.value = 100;
967 }
968
969 {
971 let guard = container1.read().unwrap();
972 assert_eq!(guard.value, 100);
973 }
974
975 drop(container);
977 drop(container1);
978 drop(container2);
979
980 assert!(weak1.upgrade().is_none());
982 assert!(weak2.upgrade().is_none());
983 }
984 }
985}
986
987#[cfg(test)]
989#[cfg(feature = "tokio-sync")]
990mod tokio_tests {
991 use super::*;
992 use tokio::runtime::Runtime;
993
994 #[derive(Debug, Clone, PartialEq)]
995 struct TestStruct {
996 value: i32,
997 }
998
999 #[test]
1000 fn test_tokio_read_access() {
1001 let rt = Runtime::new().unwrap();
1002 rt.block_on(async {
1003 let container = SharedContainer::new(TestStruct { value: 42 });
1004
1005 assert!(container.read().is_none());
1007
1008 let guard = container.read_async().await;
1010 assert_eq!(guard.value, 42);
1011 });
1012 }
1013
1014 #[test]
1015 fn test_tokio_write_access() {
1016 let rt = Runtime::new().unwrap();
1017 rt.block_on(async {
1018 let container = SharedContainer::new(TestStruct { value: 42 });
1019
1020 assert!(container.write().is_none());
1022
1023 {
1025 let mut guard = container.write_async().await;
1026 guard.value = 100;
1027 }
1028
1029 let guard = container.read_async().await;
1031 assert_eq!(guard.value, 100);
1032 });
1033 }
1034
1035 #[test]
1036 fn test_tokio_clone_container() {
1037 let rt = Runtime::new().unwrap();
1038 rt.block_on(async {
1039 let container1 = SharedContainer::new(TestStruct { value: 42 });
1040 let container2 = container1.clone();
1041
1042 {
1044 let mut guard = container2.write_async().await;
1045 guard.value = 100;
1046 }
1047
1048 let guard = container1.read_async().await;
1050 assert_eq!(guard.value, 100);
1051 });
1052 }
1053
1054 #[test]
1055 fn test_tokio_weak_ref() {
1056 let rt = Runtime::new().unwrap();
1057 rt.block_on(async {
1058 let container = SharedContainer::new(TestStruct { value: 42 });
1059
1060 let weak = container.downgrade();
1062
1063 let container2 = weak.upgrade().unwrap();
1065
1066 {
1068 let mut guard = container2.write_async().await;
1069 guard.value = 100;
1070 }
1071
1072 {
1074 let guard = container.read_async().await;
1075 assert_eq!(guard.value, 100);
1076 }
1077
1078 drop(container);
1080 drop(container2);
1081
1082 assert!(weak.upgrade().is_none());
1084 });
1085 }
1086}
1087
1088#[cfg(test)]
1091#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
1092mod wasm_tests {
1093 use super::*;
1094
1095 #[derive(Debug, Clone, PartialEq)]
1096 struct TestStruct {
1097 value: i32,
1098 }
1099
1100 #[test]
1101 fn test_wasm_read_access() {
1102 let container = SharedContainer::new(TestStruct { value: 42 });
1103
1104 let guard = container.read().unwrap();
1106 assert_eq!(guard.value, 42);
1107 }
1108
1109 #[test]
1110 fn test_wasm_write_access() {
1111 let container = SharedContainer::new(TestStruct { value: 42 });
1112
1113 {
1115 let mut guard = container.write().unwrap();
1116 guard.value = 100;
1117 }
1118
1119 let guard = container.read().unwrap();
1121 assert_eq!(guard.value, 100);
1122 }
1123
1124 #[test]
1125 fn test_wasm_borrow_conflict() {
1126 let container = SharedContainer::new(TestStruct { value: 42 });
1127
1128 let _guard = container.read().unwrap();
1130
1131 assert!(container.write().is_none());
1133 }
1134
1135 #[test]
1136 fn test_wasm_multiple_reads() {
1137 let container = SharedContainer::new(TestStruct { value: 42 });
1138
1139 let _guard1 = container.read().unwrap();
1141 let guard2 = container.read().unwrap();
1142
1143 assert_eq!(guard2.value, 42);
1144 }
1145
1146 #[test]
1147 fn test_wasm_weak_ref() {
1148 let container = SharedContainer::new(TestStruct { value: 42 });
1149 let weak = container.downgrade();
1150
1151 let container2 = weak.upgrade().unwrap();
1153 assert_eq!(container2.read().unwrap().value, 42);
1154
1155 drop(container);
1157 drop(container2);
1158 assert!(weak.upgrade().is_none());
1159 }
1160}