63
63
#![ allow( dead_code) ]
64
64
65
65
use core:: cell:: UnsafeCell ;
66
+ use core:: mem;
67
+ use core:: sync:: atomic:: Atomic ;
66
68
67
69
mod rc_alloc;
68
70
mod rc_layout;
@@ -85,3 +87,83 @@ impl RefCounts {
85
87
Self { weak : UnsafeCell :: new ( 1 ) , strong : UnsafeCell :: new ( strong_count) }
86
88
}
87
89
}
90
+
91
+ /// The return value type for `RefCounter::make_mut`.
92
+ #[ cfg( not( no_global_oom_handling) ) ]
93
+ pub ( crate ) enum MakeMutStrategy {
94
+ /// The strong reference count is 1, but weak reference count (including the one shared by all
95
+ /// strong reference count) is more than 1. Before returning, the strong reference count has
96
+ /// been set to zero to prevent new strong pointers from being created through upgrading from
97
+ /// weak pointers.
98
+ Move ,
99
+ /// The strong count is more than 1.
100
+ Clone ,
101
+ }
102
+
103
+ /// A trait for `rc` and `sync` modules to define their reference-counting behaviors.
104
+ ///
105
+ /// # Safety
106
+ ///
107
+ /// - Each method must be implemented according to its description.
108
+ /// - `Self` must have transparent representation over `UnsafeCell<usize>` and every valid
109
+ /// `UnsafeCell<usize>` can also be reinterpreted as a valid `Self`.
110
+ /// - `Self` must have alignment no greater than `align_of::<Atomic<usize>>()`.
111
+ pub ( crate ) unsafe trait RefCounter : Sized {
112
+ const VERIFY_LAYOUT : ( ) = {
113
+ assert ! ( size_of:: <Self >( ) == size_of:: <UnsafeCell <usize >>( ) ) ;
114
+ assert ! ( align_of:: <Self >( ) <= align_of:: <Atomic <usize >>( ) ) ;
115
+ } ;
116
+
117
+ /// Returns a reference to `Self` from a reference to `UnsafeCell<usize>`.
118
+ ///
119
+ /// # Safety
120
+ ///
121
+ /// - `count` must only be handled by the same `RefCounter` implementation.
122
+ /// - The location of `count` must have enough alignment for storing `Atomic<usize>`.
123
+ unsafe fn from_raw_counter ( count : & UnsafeCell < usize > ) -> & Self {
124
+ ( ) = Self :: VERIFY_LAYOUT ;
125
+
126
+ // SAFETY: The alignment requirement is guaranteed by both trait implementor and caller.
127
+ // Trait implementor guarantees the alignment of `Self` is not greater than the alignment of
128
+ // `Atomic<usize>`, and caller guarantees that the alignment of `count` is enough for
129
+ // storing `Atomic<usize>`.
130
+ unsafe { mem:: transmute ( count) }
131
+ }
132
+
133
+ /// Increments the reference counter. The process will abort if overflow happens.
134
+ fn increment ( & self ) ;
135
+
136
+ /// Decrements the reference counter. Returns whether the reference count becomes zero after
137
+ /// decrementing.
138
+ fn decrement ( & self ) -> bool ;
139
+
140
+ /// Increments the reference counter if and only if the reference count is non-zero. Returns
141
+ /// whether incrementing is performed.
142
+ fn try_upgrade ( & self ) -> bool ;
143
+
144
+ /// Increments the reference counter. If `self` needs to be called with by both
145
+ /// `downgrade_increment_weak` and `is_unique` as the `weak_count` argument concurrently, both
146
+ /// operations will be performed atomically.
147
+ fn downgrade_increment_weak ( & self ) ;
148
+
149
+ /// Decrements the reference counter if and only if the reference count is 1. Returns true if
150
+ /// decrementing is performed.
151
+ fn try_lock_strong_count ( & self ) -> bool ;
152
+
153
+ /// Sets the reference count to 1.
154
+ fn unlock_strong_count ( & self ) ;
155
+
156
+ /// Returns whether both `strong_count` and `weak_count` are 1. If `weak_count` needs to be
157
+ /// called with by both `downgrade_increment_weak` and `is_unique` concurrently, both operations
158
+ /// will be performed atomically.
159
+ fn is_unique ( strong_count : & Self , weak_count : & Self ) -> bool ;
160
+
161
+ /// Determines how to make a mutable reference safely to a reference counted value.
162
+ ///
163
+ /// - If both strong count and weak count are 1, returns `None`.
164
+ /// - If strong count is 1 and weak count is greater than 1, returns
165
+ /// `Some(MakeMutStrategy::Move)`.
166
+ /// - If strong count is greater than 1, returns `Some(MakeMutStrategy::Clone)`.
167
+ #[ cfg( not( no_global_oom_handling) ) ]
168
+ fn make_mut ( strong_count : & Self , weak_count : & Self ) -> Option < MakeMutStrategy > ;
169
+ }
0 commit comments