1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use core::ptr;

use alloc::rc::Weak as RcWeak;
use alloc::sync::Weak;

use crate::RefCnt;

unsafe impl<T> RefCnt for Weak<T> {
    type Base = T;
    fn as_ptr(me: &Self) -> *mut T {
        if Weak::ptr_eq(&Weak::new(), me) {
            ptr::null_mut()
        } else {
            Weak::as_ptr(me) as *mut T
        }
    }
    fn into_ptr(me: Self) -> *mut T {
        if Weak::ptr_eq(&Weak::new(), &me) {
            ptr::null_mut()
        } else {
            Weak::into_raw(me) as *mut T
        }
    }
    unsafe fn from_ptr(ptr: *const T) -> Self {
        if ptr.is_null() {
            Weak::new()
        } else {
            Weak::from_raw(ptr)
        }
    }
}

unsafe impl<T> RefCnt for RcWeak<T> {
    type Base = T;
    fn as_ptr(me: &Self) -> *mut T {
        if RcWeak::ptr_eq(&RcWeak::new(), me) {
            ptr::null_mut()
        } else {
            RcWeak::as_ptr(me) as *mut T
        }
    }
    fn into_ptr(me: Self) -> *mut T {
        if RcWeak::ptr_eq(&RcWeak::new(), &me) {
            ptr::null_mut()
        } else {
            RcWeak::into_raw(me) as *mut T
        }
    }
    unsafe fn from_ptr(ptr: *const T) -> Self {
        if ptr.is_null() {
            RcWeak::new()
        } else {
            RcWeak::from_raw(ptr)
        }
    }
}

macro_rules! t {
    ($name: ident, $strategy: ty) => {
        #[cfg(test)]
        mod $name {
            use alloc::sync::{Arc, Weak};

            use crate::ArcSwapAny;

            #[allow(deprecated)] // We use "deprecated" testing strategies in here.
            type ArcSwapWeak<T> = ArcSwapAny<Weak<T>, $strategy>;

            // Convert to weak, push it through the shared and pull it out again.
            #[test]
            fn there_and_back() {
                let data = Arc::new("Hello");
                let shared = ArcSwapWeak::new(Arc::downgrade(&data));
                assert_eq!(1, Arc::strong_count(&data));
                assert_eq!(1, Arc::weak_count(&data));
                let weak = shared.load();
                assert_eq!("Hello", *weak.upgrade().unwrap());
                assert!(Arc::ptr_eq(&data, &weak.upgrade().unwrap()));
            }

            // Replace a weak pointer with a NULL one
            #[test]
            fn reset() {
                let data = Arc::new("Hello");
                let shared = ArcSwapWeak::new(Arc::downgrade(&data));
                assert_eq!(1, Arc::strong_count(&data));
                assert_eq!(1, Arc::weak_count(&data));

                // An empty weak (eg. NULL)
                shared.store(Weak::new());
                assert_eq!(1, Arc::strong_count(&data));
                assert_eq!(0, Arc::weak_count(&data));

                let weak = shared.load();
                assert!(weak.upgrade().is_none());
            }

            // Destroy the underlying data while the weak is still stored inside. Should make it go
            // NULL-ish
            #[test]
            fn destroy() {
                let data = Arc::new("Hello");
                let shared = ArcSwapWeak::new(Arc::downgrade(&data));

                drop(data);
                let weak = shared.load();
                assert!(weak.upgrade().is_none());
            }
        }
    };
}

t!(tests_default, crate::DefaultStrategy);
#[cfg(feature = "internal-test-strategies")]
t!(
    tests_full_slots,
    crate::strategy::test_strategies::FillFastSlots
);