Coverage Report

Created: 2026-07-13 08:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.9.1/src/ref_cnt.rs
Line
Count
Source
1
use core::mem;
2
#[rustversion::since(1.39)]
3
use core::pin::Pin;
4
use core::ptr;
5
6
use crate::imports::{Arc, Rc};
7
8
/// A trait describing smart reference counted pointers.
9
///
10
/// Note that in a way [`Option<Arc<T>>`][Option] is also a smart reference counted pointer, just
11
/// one that can hold NULL.
12
///
13
/// The trait is unsafe, because a wrong implementation will break the [ArcSwapAny]
14
/// implementation and lead to UB.
15
///
16
/// This is not actually expected for downstream crate to implement, this is just means to reuse
17
/// code for [Arc] and [`Option<Arc>`][Option] variants. However, it is theoretically possible (if
18
/// you have your own [Arc] implementation).
19
///
20
/// It is also implemented for [Rc], but that is not considered very useful (because the
21
/// [ArcSwapAny] is not `Send` or `Sync`, therefore there's very little advantage for it to be
22
/// atomic).
23
///
24
/// # Safety
25
///
26
/// Aside from the obvious properties (like that incrementing and decrementing a reference count
27
/// cancel each out and that having less references tracked than how many things actually point to
28
/// the value is fine as long as the count doesn't drop to 0), it also must satisfy that if two
29
/// pointers have the same value, they point to the same object. This is specifically not true for
30
/// ZSTs, but it is true for `Arc`s of ZSTs, because they have the reference counts just after the
31
/// value. It would be fine to point to a type-erased version of the same object, though (if one
32
/// could use this trait with unsized types in the first place).
33
///
34
/// Furthermore, the type should be Pin (eg. if the type is cloned or moved, it should still
35
/// point/deref to the same place in memory).
36
///
37
/// [Arc]: std::sync::Arc
38
/// [Rc]: std::rc::Rc
39
/// [ArcSwapAny]: crate::ArcSwapAny
40
pub unsafe trait RefCnt: Clone {
41
    /// The base type the pointer points to.
42
    type Base;
43
44
    /// Converts the smart pointer into a raw pointer, without affecting the reference count.
45
    ///
46
    /// This can be seen as kind of freezing the pointer ‒ it'll be later converted back using
47
    /// [`from_ptr`](#method.from_ptr).
48
    ///
49
    /// The pointer must point to the value stored (and the value must be the same as one returned
50
    /// by [`as_ptr`](#method.as_ptr).
51
    fn into_ptr(me: Self) -> *mut Self::Base;
52
53
    /// Provides a view into the smart pointer as a raw pointer.
54
    ///
55
    /// This must not affect the reference count ‒ the pointer is only borrowed.
56
    fn as_ptr(me: &Self) -> *mut Self::Base;
57
58
    /// Converts a raw pointer back into the smart pointer, without affecting the reference count.
59
    ///
60
    /// This is only called on values previously returned by [`into_ptr`](#method.into_ptr).
61
    /// However, it is not guaranteed to be 1:1 relation ‒ `from_ptr` may be called more times than
62
    /// `into_ptr` temporarily provided the reference count never drops under 1 during that time
63
    /// (the implementation sometimes owes a reference). These extra pointers will either be
64
    /// converted back using `into_ptr` or forgotten.
65
    ///
66
    /// # Safety
67
    ///
68
    /// This must not be called by code outside of this crate.
69
    unsafe fn from_ptr(ptr: *const Self::Base) -> Self;
70
71
    /// Increments the reference count by one.
72
    ///
73
    /// Return the pointer to the inner thing as a side effect.
74
62.9M
    fn inc(me: &Self) -> *mut Self::Base {
75
62.9M
        Self::into_ptr(Self::clone(me))
76
62.9M
    }
<core::option::Option<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>>> as arc_swap::ref_cnt::RefCnt>::inc
Line
Count
Source
74
62.9M
    fn inc(me: &Self) -> *mut Self::Base {
75
62.9M
        Self::into_ptr(Self::clone(me))
76
62.9M
    }
Unexecuted instantiation: <alloc::sync::Arc<bytes::bytes::Bytes> as arc_swap::ref_cnt::RefCnt>::inc
<alloc::sync::Arc<(u64, std::time::Instant)> as arc_swap::ref_cnt::RefCnt>::inc
Line
Count
Source
74
52.6k
    fn inc(me: &Self) -> *mut Self::Base {
75
52.6k
        Self::into_ptr(Self::clone(me))
76
52.6k
    }
Unexecuted instantiation: <_ as arc_swap::ref_cnt::RefCnt>::inc
77
78
    /// Decrements the reference count by one.
79
    ///
80
    /// Note this is called on a raw pointer (one previously returned by
81
    /// [`into_ptr`](#method.into_ptr). This may lead to dropping of the reference count to 0 and
82
    /// destruction of the internal pointer.
83
    ///
84
    /// # Safety
85
    ///
86
    /// This must not be called by code outside of this crate.
87
954k
    unsafe fn dec(ptr: *const Self::Base) {
88
954k
        drop(Self::from_ptr(ptr));
89
954k
    }
<core::option::Option<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>>> as arc_swap::ref_cnt::RefCnt>::dec
Line
Count
Source
87
928k
    unsafe fn dec(ptr: *const Self::Base) {
88
928k
        drop(Self::from_ptr(ptr));
89
928k
    }
Unexecuted instantiation: <alloc::sync::Arc<bytes::bytes::Bytes> as arc_swap::ref_cnt::RefCnt>::dec
<alloc::sync::Arc<(u64, std::time::Instant)> as arc_swap::ref_cnt::RefCnt>::dec
Line
Count
Source
87
26.2k
    unsafe fn dec(ptr: *const Self::Base) {
88
26.2k
        drop(Self::from_ptr(ptr));
89
26.2k
    }
Unexecuted instantiation: <_ as arc_swap::ref_cnt::RefCnt>::dec
90
}
91
92
unsafe impl<T> RefCnt for Arc<T> {
93
    type Base = T;
94
52.4M
    fn into_ptr(me: Arc<T>) -> *mut T {
95
52.4M
        Arc::into_raw(me) as *mut T
96
52.4M
    }
<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>> as arc_swap::ref_cnt::RefCnt>::into_ptr
Line
Count
Source
94
52.3M
    fn into_ptr(me: Arc<T>) -> *mut T {
95
52.3M
        Arc::into_raw(me) as *mut T
96
52.3M
    }
Unexecuted instantiation: <alloc::sync::Arc<bytes::bytes::Bytes> as arc_swap::ref_cnt::RefCnt>::into_ptr
<alloc::sync::Arc<(u64, std::time::Instant)> as arc_swap::ref_cnt::RefCnt>::into_ptr
Line
Count
Source
94
105k
    fn into_ptr(me: Arc<T>) -> *mut T {
95
105k
        Arc::into_raw(me) as *mut T
96
105k
    }
Unexecuted instantiation: <alloc::sync::Arc<_> as arc_swap::ref_cnt::RefCnt>::into_ptr
97
90.0k
    fn as_ptr(me: &Arc<T>) -> *mut T {
98
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
99
        // intention as
100
        //
101
        // me as &T as *const T as *mut T
102
        //
103
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
104
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
105
        // Then we can use into_raw (which preserves not having the ref count).
106
        //
107
        // We need to "revert" the changes we did. In current std implementation, the combination
108
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
109
        // and that read shall be paired with forget to properly "close the brackets". In future
110
        // versions of STD, these may become something else that's not really no-op (unlikely, but
111
        // possible), so we future-proof it a bit.
112
113
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
114
90.0k
        let ptr = Arc::into_raw(unsafe { ptr::read(me) });
115
90.0k
        let ptr = ptr as *mut T;
116
117
        // SAFETY: We got the pointer from into_raw just above
118
90.0k
        mem::forget(unsafe { Arc::from_raw(ptr) });
119
120
90.0k
        ptr
121
90.0k
    }
<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>> as arc_swap::ref_cnt::RefCnt>::as_ptr
Line
Count
Source
97
2
    fn as_ptr(me: &Arc<T>) -> *mut T {
98
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
99
        // intention as
100
        //
101
        // me as &T as *const T as *mut T
102
        //
103
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
104
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
105
        // Then we can use into_raw (which preserves not having the ref count).
106
        //
107
        // We need to "revert" the changes we did. In current std implementation, the combination
108
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
109
        // and that read shall be paired with forget to properly "close the brackets". In future
110
        // versions of STD, these may become something else that's not really no-op (unlikely, but
111
        // possible), so we future-proof it a bit.
112
113
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
114
2
        let ptr = Arc::into_raw(unsafe { ptr::read(me) });
115
2
        let ptr = ptr as *mut T;
116
117
        // SAFETY: We got the pointer from into_raw just above
118
2
        mem::forget(unsafe { Arc::from_raw(ptr) });
119
120
2
        ptr
121
2
    }
Unexecuted instantiation: <alloc::sync::Arc<bytes::bytes::Bytes> as arc_swap::ref_cnt::RefCnt>::as_ptr
<alloc::sync::Arc<(u64, std::time::Instant)> as arc_swap::ref_cnt::RefCnt>::as_ptr
Line
Count
Source
97
90.0k
    fn as_ptr(me: &Arc<T>) -> *mut T {
98
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
99
        // intention as
100
        //
101
        // me as &T as *const T as *mut T
102
        //
103
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
104
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
105
        // Then we can use into_raw (which preserves not having the ref count).
106
        //
107
        // We need to "revert" the changes we did. In current std implementation, the combination
108
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
109
        // and that read shall be paired with forget to properly "close the brackets". In future
110
        // versions of STD, these may become something else that's not really no-op (unlikely, but
111
        // possible), so we future-proof it a bit.
112
113
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
114
90.0k
        let ptr = Arc::into_raw(unsafe { ptr::read(me) });
115
90.0k
        let ptr = ptr as *mut T;
116
117
        // SAFETY: We got the pointer from into_raw just above
118
90.0k
        mem::forget(unsafe { Arc::from_raw(ptr) });
119
120
90.0k
        ptr
121
90.0k
    }
Unexecuted instantiation: <alloc::sync::Arc<_> as arc_swap::ref_cnt::RefCnt>::as_ptr
122
52.5M
    unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
123
52.5M
        Arc::from_raw(ptr)
124
52.5M
    }
<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>> as arc_swap::ref_cnt::RefCnt>::from_ptr
Line
Count
Source
122
52.3M
    unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
123
52.3M
        Arc::from_raw(ptr)
124
52.3M
    }
Unexecuted instantiation: <alloc::sync::Arc<bytes::bytes::Bytes> as arc_swap::ref_cnt::RefCnt>::from_ptr
<alloc::sync::Arc<(u64, std::time::Instant)> as arc_swap::ref_cnt::RefCnt>::from_ptr
Line
Count
Source
122
195k
    unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
123
195k
        Arc::from_raw(ptr)
124
195k
    }
Unexecuted instantiation: <alloc::sync::Arc<_> as arc_swap::ref_cnt::RefCnt>::from_ptr
125
}
126
127
unsafe impl<T> RefCnt for Rc<T> {
128
    type Base = T;
129
0
    fn into_ptr(me: Rc<T>) -> *mut T {
130
0
        Rc::into_raw(me) as *mut T
131
0
    }
132
0
    fn as_ptr(me: &Rc<T>) -> *mut T {
133
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
134
        // intention as
135
        //
136
        // me as &T as *const T as *mut T
137
        //
138
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
139
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
140
        // Then we can use into_raw (which preserves not having the ref count).
141
        //
142
        // We need to "revert" the changes we did. In current std implementation, the combination
143
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
144
        // and that read shall be paired with forget to properly "close the brackets". In future
145
        // versions of STD, these may become something else that's not really no-op (unlikely, but
146
        // possible), so we future-proof it a bit.
147
148
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
149
0
        let ptr = Rc::into_raw(unsafe { ptr::read(me) });
150
0
        let ptr = ptr as *mut T;
151
152
        // SAFETY: We got the pointer from into_raw just above
153
0
        mem::forget(unsafe { Rc::from_raw(ptr) });
154
155
0
        ptr
156
0
    }
157
0
    unsafe fn from_ptr(ptr: *const T) -> Rc<T> {
158
0
        Rc::from_raw(ptr)
159
0
    }
160
}
161
162
unsafe impl<T: RefCnt> RefCnt for Option<T> {
163
    type Base = T::Base;
164
64.6M
    fn into_ptr(me: Option<T>) -> *mut T::Base {
165
64.6M
        me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
166
64.6M
    }
<core::option::Option<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>>> as arc_swap::ref_cnt::RefCnt>::into_ptr
Line
Count
Source
164
64.6M
    fn into_ptr(me: Option<T>) -> *mut T::Base {
165
64.6M
        me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
166
64.6M
    }
Unexecuted instantiation: <core::option::Option<_> as arc_swap::ref_cnt::RefCnt>::into_ptr
167
2
    fn as_ptr(me: &Option<T>) -> *mut T::Base {
168
2
        me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
169
2
    }
<core::option::Option<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>>> as arc_swap::ref_cnt::RefCnt>::as_ptr
Line
Count
Source
167
2
    fn as_ptr(me: &Option<T>) -> *mut T::Base {
168
2
        me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
169
2
    }
Unexecuted instantiation: <core::option::Option<_> as arc_swap::ref_cnt::RefCnt>::as_ptr
170
64.6M
    unsafe fn from_ptr(ptr: *const T::Base) -> Option<T> {
171
64.6M
        if ptr.is_null() {
172
12.2M
            None
173
        } else {
174
52.3M
            Some(T::from_ptr(ptr))
175
        }
176
64.6M
    }
<core::option::Option<alloc::sync::Arc<crossbeam_deque::deque::Stealer<async_task::runnable::Runnable>>> as arc_swap::ref_cnt::RefCnt>::from_ptr
Line
Count
Source
170
64.6M
    unsafe fn from_ptr(ptr: *const T::Base) -> Option<T> {
171
64.6M
        if ptr.is_null() {
172
12.2M
            None
173
        } else {
174
52.3M
            Some(T::from_ptr(ptr))
175
        }
176
64.6M
    }
Unexecuted instantiation: <core::option::Option<_> as arc_swap::ref_cnt::RefCnt>::from_ptr
177
}
178
179
// Pin is only available since Rust 1.33, but Pin::into_inner is from 1.39.
180
#[rustversion::since(1.39)]
181
unsafe impl<T> RefCnt for Pin<Arc<T>> {
182
    type Base = T;
183
184
0
    fn into_ptr(me: Pin<Arc<T>>) -> *mut T {
185
        // SAFETY: We only expose an opaque pointer, which maintains the `Pin` invariant.
186
0
        Arc::into_raw(unsafe { Pin::into_inner_unchecked(me) }) as *mut T
187
0
    }
188
189
0
    fn as_ptr(me: &Pin<Arc<T>>) -> *mut T {
190
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
191
        // intention as
192
        //
193
        // me as &T as *const T as *mut T
194
        //
195
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
196
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
197
        // Then we can use into_raw (which preserves not having the ref count).
198
        //
199
        // We need to "revert" the changes we did. In current std implementation, the combination
200
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
201
        // and that read shall be paired with forget to properly "close the brackets". In future
202
        // versions of STD, these may become something else that's not really no-op (unlikely, but
203
        // possible), so we future-proof it a bit.
204
205
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
206
        // We only expose an opaque pointer, which maintains the `Pin` invariant.
207
0
        let me = Arc::into_raw(unsafe { Pin::into_inner_unchecked(ptr::read(me)) });
208
0
        let ptr = me as *mut T;
209
210
        // SAFETY: We got the pointer from into_raw just above
211
0
        mem::forget(unsafe { Arc::from_raw(ptr) });
212
213
0
        ptr
214
0
    }
215
216
0
    unsafe fn from_ptr(ptr: *const T) -> Self {
217
        // SAFETY: `ptr` came from a previous `{into_ptr,as_ptr}` call, which is pinned.
218
0
        unsafe { Pin::new_unchecked(Arc::from_raw(ptr)) }
219
0
    }
220
}
221
222
// Pin is only available since Rust 1.33, but Pin::into_inner is from 1.39.
223
#[rustversion::since(1.39)]
224
unsafe impl<T> RefCnt for Pin<Rc<T>> {
225
    type Base = T;
226
227
0
    fn into_ptr(me: Pin<Rc<T>>) -> *mut T {
228
        // SAFETY: We only expose an opaque pointer, which maintains the `Pin` invariant.
229
0
        Rc::into_raw(unsafe { Pin::into_inner_unchecked(me) }) as *mut T
230
0
    }
231
232
0
    fn as_ptr(me: &Pin<Rc<T>>) -> *mut T {
233
        // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
234
        // intention as
235
        //
236
        // me as &T as *const T as *mut T
237
        //
238
        // We first create a "shallow copy" of me - one that doesn't really own its ref count
239
        // (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
240
        // Then we can use into_raw (which preserves not having the ref count).
241
        //
242
        // We need to "revert" the changes we did. In current std implementation, the combination
243
        // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
244
        // and that read shall be paired with forget to properly "close the brackets". In future
245
        // versions of STD, these may become something else that's not really no-op (unlikely, but
246
        // possible), so we future-proof it a bit.
247
248
        // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
249
        // We only expose an opaque pointer, which maintains the `Pin` invariant.
250
0
        let me = Rc::into_raw(unsafe { Pin::into_inner_unchecked(ptr::read(me)) });
251
0
        let ptr = me as *mut T;
252
253
        // SAFETY: We got the pointer from into_raw just above
254
0
        mem::forget(unsafe { Rc::from_raw(ptr) });
255
256
0
        ptr
257
0
    }
258
259
0
    unsafe fn from_ptr(ptr: *const T) -> Self {
260
        // SAFETY: `ptr` came from a previous `{into_ptr,as_ptr}` call, which is pinned.
261
0
        unsafe { Pin::new_unchecked(Rc::from_raw(ptr)) }
262
0
    }
263
}
264
265
#[cfg(test)]
266
mod tests {
267
    use super::*;
268
269
    #[test]
270
    fn ref_cnt_arc() {
271
        struct Data(u32);
272
273
        let arc = Arc::new(Data(114514));
274
        let ptr = RefCnt::as_ptr(&arc);
275
        assert_eq!(ptr, RefCnt::into_ptr(arc));
276
277
        let arc: Arc<Data> = unsafe { RefCnt::from_ptr(ptr) };
278
        assert_eq!(arc.0, 114514);
279
        assert_eq!(ptr, RefCnt::as_ptr(&arc));
280
        assert_eq!(ptr, RefCnt::into_ptr(arc));
281
282
        // Let it drop.
283
        let _: Arc<Data> = unsafe { RefCnt::from_ptr(ptr) };
284
    }
285
286
    // Pin is only available since Rust 1.33, but Pin::into_inner is from 1.39.
287
    #[rustversion::since(1.39)]
288
    mod pin {
289
        use super::*;
290
        use core::marker::PhantomPinned;
291
292
        #[test]
293
        fn ref_cnt_pin_arc() {
294
            struct Unmovable {
295
                value: u32,
296
                _phantom: PhantomPinned,
297
            }
298
299
            let pinned = Arc::pin(Unmovable {
300
                value: 114514,
301
                _phantom: PhantomPinned,
302
            });
303
            let ptr = RefCnt::as_ptr(&pinned);
304
            assert_eq!(ptr, RefCnt::into_ptr(pinned));
305
306
            let pinned: Pin<Arc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
307
            assert_eq!(pinned.value, 114514);
308
            assert_eq!(ptr, RefCnt::as_ptr(&pinned));
309
            assert_eq!(ptr, RefCnt::into_ptr(pinned));
310
311
            // Let it drop.
312
            let _: Pin<Arc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
313
        }
314
315
        #[test]
316
        fn ref_cnt_pin_rc() {
317
            struct Unmovable {
318
                value: u32,
319
                _phantom: PhantomPinned,
320
            }
321
322
            let pinned = Rc::pin(Unmovable {
323
                value: 114514,
324
                _phantom: PhantomPinned,
325
            });
326
            let ptr = RefCnt::as_ptr(&pinned);
327
            assert_eq!(ptr, RefCnt::into_ptr(pinned));
328
329
            let pinned: Pin<Rc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
330
            assert_eq!(pinned.value, 114514);
331
            assert_eq!(ptr, RefCnt::as_ptr(&pinned));
332
            assert_eq!(ptr, RefCnt::into_ptr(pinned));
333
334
            // Let it drop.
335
            let _: Pin<Rc<Unmovable>> = unsafe { RefCnt::from_ptr(ptr) };
336
        }
337
    }
338
}