sdd/shared.rs
1use std::mem::forget;
2use std::ops::Deref;
3use std::panic::UnwindSafe;
4use std::ptr::NonNull;
5
6use super::ref_counted::RefCounted;
7use super::{Guard, Ptr};
8
9/// [`Shared`] is a reference-counted handle to an instance.
10///
11/// The instance is passed to the EBR garbage collector when the last strong reference is dropped.
12#[derive(Debug)]
13pub struct Shared<T> {
14 ptr: NonNull<RefCounted<T>>,
15}
16
17impl<T: 'static> Shared<T> {
18 /// Creates a new [`Shared`].
19 ///
20 /// The type of the instance must be determined at compile-time, must not contain non-static
21 /// references, and must not be a non-static reference since the instance can theoretically
22 /// survive the process. For instance, `struct Disallowed<'l, T>(&'l T)` is not allowed,
23 /// because an instance of the type cannot outlive `'l` whereas the garbage collector does not
24 /// guarantee that the instance is dropped within `'l`.
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// use sdd::Shared;
30 ///
31 /// let shared: Shared<usize> = Shared::new(31);
32 /// ```
33 #[inline]
34 pub fn new(t: T) -> Self {
35 Self::new_with(|| t)
36 }
37
38 /// Creates a new [`Shared`] with the provided function.
39 ///
40 /// This function is identical to [`Shared::new`] except that the value is constructed after
41 /// memory allocation.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use sdd::Shared;
47 ///
48 /// let shared: Shared<String> = Shared::new_with(|| String::from("hello"));
49 /// ```
50 #[inline]
51 pub fn new_with<F: FnOnce() -> T>(f: F) -> Shared<T> {
52 Shared {
53 ptr: RefCounted::new_shared(f),
54 }
55 }
56}
57
58impl<T> Shared<T> {
59 /// Creates a new [`Shared`] without checking the lifetime of `T`.
60 ///
61 /// # Safety
62 ///
63 /// `T::drop` can be run after the last strong reference is dropped, therefore it is safe only
64 /// if `T::drop` does not access short-lived data or [`std::mem::needs_drop`] is `false` for
65 /// `T`. Otherwise, the instance must be manually dropped by invoking [`Self::drop_in_place`]
66 /// within the lifetime of `T`.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use sdd::Shared;
72 ///
73 /// let hello = String::from("hello");
74 /// let shared: Shared<&str> = unsafe { Shared::new_unchecked(hello.as_str()) };
75 ///
76 /// assert!(unsafe { shared.drop_in_place() });
77 /// ```
78 #[inline]
79 pub unsafe fn new_unchecked(t: T) -> Self {
80 unsafe { Self::new_with_unchecked(|| t) }
81 }
82
83 /// Creates a new [`Shared`] with the provided function without checking the lifetime of `T`.
84 ///
85 /// This function is identical to [`Shared::new_unchecked`] except that the value is constructed
86 /// after memory allocation.
87 ///
88 /// # Safety
89 ///
90 /// See [`Shared::new_unchecked`].
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use sdd::Shared;
96 ///
97 /// let hello = String::from("hello");
98 /// let shared: Shared<&str> = unsafe { Shared::new_with_unchecked(|| hello.as_str()) };
99 ///
100 /// assert!(unsafe { shared.drop_in_place() });
101 /// ```
102 #[inline]
103 pub unsafe fn new_with_unchecked<F: FnOnce() -> T>(f: F) -> Shared<T> {
104 Shared {
105 ptr: RefCounted::new_shared(f),
106 }
107 }
108
109 /// Returns a [`Ptr`] to the instance that may live as long as the supplied [`Guard`].
110 ///
111 /// # Examples
112 ///
113 /// ```
114 /// use sdd::{Guard, Shared};
115 ///
116 /// let shared: Shared<usize> = Shared::new(37);
117 /// let guard = Guard::new();
118 /// let ptr = shared.get_guarded_ptr(&guard);
119 /// drop(shared);
120 ///
121 /// assert_eq!(*ptr.as_ref().unwrap(), 37);
122 /// ```
123 #[inline]
124 #[must_use]
125 pub const fn get_guarded_ptr<'g>(&self, _guard: &'g Guard) -> Ptr<'g, T> {
126 Ptr::from(self.ptr.as_ptr())
127 }
128
129 /// Returns a reference to the instance that may live as long as the supplied [`Guard`].
130 ///
131 /// # Examples
132 ///
133 /// ```
134 /// use sdd::{Guard, Shared};
135 ///
136 /// let shared: Shared<usize> = Shared::new(37);
137 /// let guard = Guard::new();
138 /// let ref_b = shared.get_guarded_ref(&guard);
139 /// drop(shared);
140 ///
141 /// assert_eq!(*ref_b, 37);
142 /// ```
143 #[inline]
144 #[must_use]
145 pub const fn get_guarded_ref<'g>(&self, _guard: &'g Guard) -> &'g T {
146 unsafe { RefCounted::inst_non_null_ptr(self.ptr).as_ref() }
147 }
148
149 /// Returns a mutable reference to the instance if the [`Shared`] is holding the only strong
150 /// reference.
151 ///
152 /// # Safety
153 ///
154 /// The method is `unsafe` since there can be a [`Ptr`] to the instance without holding a
155 /// strong reference.
156 ///
157 /// # Examples
158 ///
159 /// ```
160 /// use sdd::Shared;
161 ///
162 /// let mut shared: Shared<usize> = Shared::new(38);
163 /// unsafe {
164 /// *shared.get_mut().unwrap() += 1;
165 /// }
166 /// assert_eq!(*shared, 39);
167 /// ```
168 #[inline]
169 pub unsafe fn get_mut(&mut self) -> Option<&mut T> {
170 unsafe { self.ptr.as_ptr().as_mut().and_then(|r| r.get_mut_shared()) }
171 }
172
173 /// Provides a raw pointer to the instance.
174 ///
175 /// # Examples
176 ///
177 /// ```
178 /// use sdd::Shared;
179 ///
180 /// let shared: Shared<usize> = Shared::new(10);
181 /// let shared_clone: Shared<usize> = shared.clone();
182 ///
183 /// assert_eq!(shared.as_ptr(), shared_clone.as_ptr());
184 /// assert_eq!(unsafe { *shared.as_ptr() }, unsafe { *shared_clone.as_ptr() });
185 /// ```
186 #[inline]
187 #[must_use]
188 pub const fn as_ptr(&self) -> *const T {
189 RefCounted::inst_non_null_ptr(self.ptr).as_ptr()
190 }
191
192 /// Provides a raw non-null pointer to the instance.
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// use sdd::Shared;
198 ///
199 /// let shared: Shared<usize> = Shared::new(10);
200 /// let shared_clone: Shared<usize> = shared.clone();
201 ///
202 /// assert_eq!(shared.as_ptr(), shared_clone.as_ptr());
203 /// assert_eq!(unsafe { *shared.as_non_null_ptr().as_ref() }, unsafe { *shared_clone.as_ptr() });
204 /// ```
205 #[inline]
206 #[must_use]
207 pub const fn as_non_null_ptr(&self) -> NonNull<T> {
208 RefCounted::inst_non_null_ptr(self.ptr)
209 }
210
211 /// Releases the strong reference by passing `self` to the given [`Guard`].
212 ///
213 /// Returns `true` if the last reference was released.
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// use sdd::Shared;
219 ///
220 /// let shared: Shared<usize> = Shared::new(47);
221 /// let shared_clone = shared.clone();
222 /// assert!(!shared.release());
223 /// assert!(shared_clone.release());
224 /// ```
225 #[inline]
226 #[must_use]
227 pub fn release(self) -> bool {
228 let released = if unsafe { (*self.ptr.as_ptr()).drop_ref() } {
229 RefCounted::pass_to_collector(self.ptr.as_ptr());
230 true
231 } else {
232 false
233 };
234 forget(self);
235 released
236 }
237
238 /// Drops the instance immediately if it has held the last reference to the instance.
239 ///
240 /// Returns `true` if the instance was dropped.
241 ///
242 /// # Safety
243 ///
244 /// The caller must ensure that there is no [`Ptr`] pointing to the instance.
245 ///
246 /// # Examples
247 ///
248 /// ```
249 /// use sdd::Shared;
250 /// use std::sync::atomic::AtomicBool;
251 /// use std::sync::atomic::Ordering::Relaxed;
252 ///
253 /// static DROPPED: AtomicBool = AtomicBool::new(false);
254 /// struct T(&'static AtomicBool);
255 /// impl Drop for T {
256 /// fn drop(&mut self) {
257 /// self.0.store(true, Relaxed);
258 /// }
259 /// }
260 ///
261 /// let shared: Shared<T> = Shared::new(T(&DROPPED));
262 /// let shared_clone = shared.clone();
263 ///
264 /// unsafe {
265 /// assert!(!shared.drop_in_place());
266 /// assert!(!DROPPED.load(Relaxed));
267 /// assert!(shared_clone.drop_in_place());
268 /// assert!(DROPPED.load(Relaxed));
269 /// }
270 /// ```
271 #[inline]
272 #[must_use]
273 pub unsafe fn drop_in_place(self) -> bool {
274 unsafe {
275 let dropped = if (*self.ptr.as_ptr()).drop_ref() {
276 RefCounted::<T>::dealloc(self.ptr.as_ptr());
277 true
278 } else {
279 false
280 };
281 forget(self);
282 dropped
283 }
284 }
285
286 /// Creates a new [`Shared`] from the given pointer.
287 #[inline]
288 pub(super) const fn from(ptr: NonNull<RefCounted<T>>) -> Self {
289 Self { ptr }
290 }
291
292 /// Returns a pointer to the [`RefCounted`].
293 #[inline]
294 pub(super) const fn underlying_ptr(&self) -> *const RefCounted<T> {
295 self.ptr.as_ptr()
296 }
297}
298
299impl<T> AsRef<T> for Shared<T> {
300 #[inline]
301 fn as_ref(&self) -> &T {
302 unsafe { &*self.ptr.as_ptr() }
303 }
304}
305
306impl<T> Clone for Shared<T> {
307 #[inline]
308 fn clone(&self) -> Self {
309 unsafe { (*self.ptr.as_ptr()).add_ref() }
310 Self { ptr: self.ptr }
311 }
312}
313
314impl<T> Deref for Shared<T> {
315 type Target = T;
316
317 #[inline]
318 fn deref(&self) -> &Self::Target {
319 self.as_ref()
320 }
321}
322
323impl<T> Drop for Shared<T> {
324 #[inline]
325 fn drop(&mut self) {
326 if unsafe { (*self.ptr.as_ptr()).drop_ref() } {
327 RefCounted::pass_to_collector(self.ptr.as_ptr());
328 }
329 }
330}
331
332impl<'g, T> TryFrom<Ptr<'g, T>> for Shared<T> {
333 type Error = Ptr<'g, T>;
334
335 #[inline]
336 fn try_from(ptr: Ptr<'g, T>) -> Result<Self, Self::Error> {
337 if let Some(shared) = ptr.get_shared() {
338 Ok(shared)
339 } else {
340 Err(ptr)
341 }
342 }
343}
344
345unsafe impl<T: Send> Send for Shared<T> {}
346
347unsafe impl<T: Send + Sync> Sync for Shared<T> {}
348
349impl<T: UnwindSafe> UnwindSafe for Shared<T> {}