Skip to main content

design/sync/
arc_ref.rs

1use std::{
2    alloc::{
3        Layout,
4        dealloc,
5    },
6    ptr::NonNull,
7    sync::atomic::Ordering,
8};
9
10use crate::{
11    ops::place::{
12        BorrowPlace,
13        CreateHandle,
14        DerefPlace,
15        PlaceHandle,
16        PlaceProxy,
17        ProjectPlace,
18        ReadPlace,
19        borrowck::{
20            AccessKind,
21            Instant,
22            Lifetime,
23            Timing,
24            UntilDrop,
25        },
26    },
27    place::Subplace,
28    sync::arc::ArcHead,
29};
30
31/// Reference into an [`Arc<T>`].
32///
33/// [`Arc<T>`]: std::sync::Arc
34pub struct ArcRef<T: ?Sized> {
35    pub(super) head: NonNull<ArcHead>,
36    pub(super) layout: Layout,
37    pub(super) data: NonNull<T>,
38}
39
40impl<T: ?Sized> Drop for ArcRef<T> {
41    fn drop(&mut self) {
42        let strong = unsafe { &(*self.head.as_ptr()).strong };
43        let old = strong.fetch_sub(1, Ordering::Relaxed);
44        if old == 1 {
45            let layout = self.layout;
46            let ptr: *mut u8 = self.head.as_ptr().cast();
47            unsafe { dealloc(ptr, layout) };
48        }
49    }
50}
51
52impl<T: ?Sized> PlaceProxy for ArcRef<T> {
53    type Target = T;
54}
55
56unsafe impl<T: ?Sized> CreateHandle<Instant> for ArcRef<T> {
57    type Handle = ArcRefHandle<T>;
58
59    const ACCESS: AccessKind = AccessKind::Shared;
60
61    unsafe fn handle_from_raw(this: *const Self) -> Self::Handle {
62        let head = unsafe { (*this).head };
63        let layout = unsafe { (*this).layout };
64        let data = unsafe { (*this).data };
65        ArcRefHandle { head, layout, data }
66    }
67}
68
69pub struct ArcRefHandle<T: ?Sized> {
70    pub(super) head: NonNull<ArcHead>,
71    pub(super) layout: Layout,
72    pub(super) data: NonNull<T>,
73}
74
75impl<T: ?Sized> PlaceHandle for ArcRefHandle<T> {
76    type Target = T;
77}
78
79unsafe impl<T> ReadPlace for ArcRefHandle<T> {
80    const ACCESS: AccessKind = AccessKind::Shared;
81    const SAFE: bool = true;
82
83    unsafe fn read_place(self) -> Self::Target {
84        unsafe { self.data.read() }
85    }
86}
87
88unsafe impl<S: Subplace> ProjectPlace<S> for ArcRefHandle<S::Source> {
89    type Projected = ArcRefHandle<S::Target>;
90
91    unsafe fn project_place(self, subplace: S) -> Self::Projected {
92        let Self { head, layout, data } = self;
93        ArcRefHandle {
94            head,
95            layout,
96            data: unsafe { data.project_place(subplace) },
97        }
98    }
99}
100
101unsafe impl<T: ?Sized> BorrowPlace<ArcRef<T>> for ArcRefHandle<T> {
102    const ACCESS: AccessKind = AccessKind::Shared;
103    type Timing = Instant;
104    const SAFE: bool = true;
105
106    unsafe fn borrow(self) -> ArcRef<T> {
107        let ArcRefHandle { head, layout, data } = self;
108        unsafe {
109            let strong = &(*head.as_ptr()).strong;
110            let old = strong.fetch_add(1, Ordering::Relaxed);
111            {
    match (&old, &0) {
        (left_val, right_val) => {
            if *left_val == *right_val {
                let kind = ::core::panicking::AssertKind::Ne;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_ne!(old, 0);
112        }
113        ArcRef { head, layout, data }
114    }
115}
116
117unsafe impl<T: ?Sized> BorrowPlace<*const T> for ArcRefHandle<T> {
118    const ACCESS: AccessKind = AccessKind::Shared;
119    type Timing = Instant;
120    const SAFE: bool = true;
121
122    unsafe fn borrow(self) -> *const T {
123        self.data.as_ptr()
124    }
125}
126
127unsafe impl<T: ?Sized> BorrowPlace<NonNull<T>> for ArcRefHandle<T> {
128    const ACCESS: AccessKind = AccessKind::Shared;
129    type Timing = Instant;
130    const SAFE: bool = true;
131
132    unsafe fn borrow(self) -> NonNull<T> {
133        self.data
134    }
135}
136
137unsafe impl<'a, T: ?Sized> BorrowPlace<&'a T> for ArcRefHandle<T> {
138    const ACCESS: AccessKind = AccessKind::Shared;
139    type Timing = Lifetime<'a>;
140    const SAFE: bool = true;
141
142    unsafe fn borrow(self) -> &'a T {
143        unsafe { self.data.as_ref() }
144    }
145}
146
147unsafe impl<T, ProxyTiming> DerefPlace<ProxyTiming, UntilDrop>
148    for ArcRefHandle<T>
149where
150    T: ?Sized + CreateHandle<ProxyTiming>,
151    ProxyTiming: Timing,
152{
153    const POINTEE_ACCESS: AccessKind = T::ACCESS;
154    const POINTER_ACCESS: AccessKind = AccessKind::Shared;
155    const SAFE: bool = true;
156
157    unsafe fn deref_place(
158        self,
159    ) -> <Self::Target as CreateHandle<ProxyTiming>>::Handle {
160        let ptr = self.data.as_ptr();
161        unsafe { T::handle_from_raw(ptr) }
162    }
163}