Skip to main content

design/sync/
arc.rs

1use std::{
2    alloc::Layout,
3    ptr::NonNull,
4    sync::{
5        Arc,
6        atomic::{
7            AtomicUsize,
8            Ordering,
9        },
10    },
11};
12
13use crate::{
14    ops::place::{
15        BorrowPlace,
16        CreateHandle,
17        PlaceHandle,
18        PlaceProxy,
19        borrowck::{
20            AccessKind,
21            Instant,
22            Lifetime,
23        },
24    },
25    sync::arc_ref::ArcRef,
26};
27
28#[repr(C, align(2))]
29struct ArcInner<T: ?Sized> {
30    strong: AtomicUsize,
31    weak: AtomicUsize,
32    data: T,
33}
34
35#[repr(C, align(2))]
36pub(super) struct ArcHead {
37    pub(super) strong: AtomicUsize,
38    pub(super) weak: AtomicUsize,
39}
40
41pub struct ArcHandle<T: ?Sized>(NonNull<ArcInner<T>>);
42
43impl<T: ?Sized> PlaceProxy for Arc<T> {
44    type Target = T;
45}
46
47unsafe impl<T: ?Sized> CreateHandle<Instant> for Arc<T> {
48    type Handle = ArcHandle<T>;
49
50    const ACCESS: AccessKind = AccessKind::Shared;
51
52    unsafe fn handle_from_raw(this: *const Self) -> Self::Handle {
53        let ptr: *const NonNull<ArcInner<T>> = this.cast();
54        let ptr: NonNull<ArcInner<T>> = unsafe { ptr.read() };
55        ArcHandle(ptr)
56    }
57}
58
59impl<T: ?Sized> PlaceHandle for ArcHandle<T> {
60    type Target = T;
61}
62
63unsafe impl<'a, T: ?Sized> BorrowPlace<&'a T> for ArcHandle<T> {
64    const ACCESS: AccessKind = AccessKind::Shared;
65    type Timing = Lifetime<'a>;
66    const SAFE: bool = true;
67
68    unsafe fn borrow(self) -> &'a T {
69        let ptr = self.0.as_ptr();
70        unsafe { &(*ptr).data }
71    }
72}
73
74unsafe impl<T: ?Sized> BorrowPlace<*const T> for ArcHandle<T> {
75    const ACCESS: AccessKind = AccessKind::Shared;
76    type Timing = Instant;
77    const SAFE: bool = true;
78
79    unsafe fn borrow(self) -> *const T {
80        let ptr = self.0.as_ptr();
81        unsafe { &raw const (*ptr).data }
82    }
83}
84
85unsafe impl<T: ?Sized> BorrowPlace<NonNull<T>> for ArcHandle<T> {
86    const ACCESS: AccessKind = AccessKind::Shared;
87    type Timing = Instant;
88    const SAFE: bool = true;
89
90    unsafe fn borrow(self) -> NonNull<T> {
91        let ptr = self.0.as_ptr();
92        unsafe { NonNull::new_unchecked(&raw mut (*ptr).data) }
93    }
94}
95
96unsafe impl<T: ?Sized> BorrowPlace<ArcRef<T>> for ArcHandle<T> {
97    const ACCESS: AccessKind = AccessKind::Shared;
98    type Timing = Instant;
99    const SAFE: bool = true;
100
101    unsafe fn borrow(self) -> ArcRef<T> {
102        let data: *mut ArcInner<T> = self.0.as_ptr();
103        let data: *mut T = unsafe { &raw mut (*data).data };
104        let layout = unsafe { Layout::for_value_raw(data) };
105        let data = unsafe { NonNull::new_unchecked(data) };
106        let head: NonNull<ArcHead> = self.0.cast();
107        unsafe {
108            let strong = &(*head.as_ptr()).strong;
109            let old = strong.fetch_add(1, Ordering::Relaxed);
110            {
    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);
111        }
112        ArcRef { head, layout, data }
113    }
114}