Skip to main content

stefans_utils/
as_arc.rs

1use std::sync::Arc;
2
3pub trait AsArc<T> {
4    #[allow(clippy::wrong_self_convention)]
5    fn as_arc(self) -> Arc<T>;
6}
7
8impl<T> AsArc<T> for Arc<T> {
9    fn as_arc(self) -> Arc<T> {
10        self
11    }
12}
13
14impl<T> AsArc<T> for &Arc<T> {
15    fn as_arc(self) -> Arc<T> {
16        self.clone()
17    }
18}
19
20impl<T> AsArc<T> for T {
21    fn as_arc(self) -> Arc<T> {
22        Arc::new(self)
23    }
24}
25
26impl<T: Clone> AsArc<T> for &T {
27    fn as_arc(self) -> Arc<T> {
28        Arc::new(self.clone())
29    }
30}
31
32impl<T> AsArc<T> for Box<T> {
33    fn as_arc(self) -> Arc<T> {
34        Arc::new(*self)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[derive(Debug, PartialEq, Default)]
43    struct MyStruct(usize);
44
45    impl Clone for MyStruct {
46        fn clone(&self) -> Self {
47            Self(self.0 + 1)
48        }
49    }
50
51    #[test]
52    fn as_arc_should_only_clone_a_ref_of_arc() {
53        let before = Arc::new(MyStruct::default());
54
55        fn takes_impl(arg: impl AsArc<MyStruct>) -> Arc<MyStruct> {
56            arg.as_arc()
57        }
58
59        assert_eq!(
60            Arc::strong_count(&before),
61            1,
62            "Arc ref count should be 1 before passing value to takes_impl"
63        );
64        assert_eq!(
65            before.0, 0,
66            "Clone count should be 0 before passing value to takes_impl"
67        );
68
69        let referenced = takes_impl(&before);
70
71        assert_eq!(
72            Arc::strong_count(&referenced),
73            2,
74            "Arc ref count should be 2 after passing reference to takes_impl"
75        );
76        assert_eq!(
77            Arc::strong_count(&before),
78            2,
79            "Arc ref count should be 2 after passing reference to takes_impl"
80        );
81        assert_eq!(
82            referenced.0, 0,
83            "Clone count should be 0 after passing reference to takes_impl"
84        );
85        assert_eq!(
86            before.0, 0,
87            "Clone count should be 0 after passing reference to takes_impl"
88        );
89
90        let moved = takes_impl(before);
91
92        assert_eq!(
93            Arc::strong_count(&referenced),
94            2,
95            "Arc ref count should be 2 after moving value to takes_impl"
96        );
97        assert_eq!(
98            Arc::strong_count(&moved),
99            2,
100            "Arc ref count should be 2 after moving value to takes_impl"
101        );
102        assert_eq!(
103            referenced.0, 0,
104            "Clone count should be 0 after moving value to takes_impl"
105        );
106        assert_eq!(
107            moved.0, 0,
108            "Clone count should be 0 after moving value to takes_impl"
109        );
110    }
111
112    #[test]
113    fn as_arc_should_only_clone_a_ref_of_inner() {
114        let before = MyStruct::default();
115
116        fn takes_impl(arg: impl AsArc<MyStruct>) -> Arc<MyStruct> {
117            arg.as_arc()
118        }
119
120        assert_eq!(
121            before.0, 0,
122            "Clone count should be 0 before passing value to takes_impl"
123        );
124
125        let arc_from_ref = takes_impl(&before);
126
127        assert_eq!(
128            arc_from_ref.0, 1,
129            "Inner clone count of arc_from_ref should be 1 after passing reference to takes_impl"
130        );
131        assert_eq!(
132            before.0, 0,
133            "Clone count of before should still be 0 after passing reference to takes_impl"
134        );
135
136        let arc_from_moved = takes_impl(before);
137
138        assert_eq!(
139            arc_from_ref.0, 1,
140            "Inner clone count of arc_from_ref should still be 1 after moving original to takes_impl"
141        );
142        assert_eq!(
143            arc_from_moved.0, 0,
144            "Inner clone count of arc_from_moved should still be 0 after moving original to takes_impl"
145        );
146    }
147}