Skip to main content

sdd/
ptr.rs

1use std::marker::PhantomData;
2use std::panic::UnwindSafe;
3use std::sync::atomic::Ordering::Relaxed;
4use std::{ptr, ptr::NonNull};
5
6use super::ref_counted::RefCounted;
7use super::{Shared, Tag};
8
9/// [`Ptr`] is a pointer that allows to safely access the pointed-to instance.
10#[derive(Debug)]
11pub struct Ptr<'g, T> {
12    ptr: *const RefCounted<T>,
13    _phantom: PhantomData<&'g T>,
14}
15
16impl<'g, T> Ptr<'g, T> {
17    /// Creates a null [`Ptr`].
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use sdd::Ptr;
23    ///
24    /// let ptr: Ptr<usize> = Ptr::null();
25    /// ```
26    #[inline]
27    #[must_use]
28    pub const fn null() -> Self {
29        Self {
30            ptr: ptr::null(),
31            _phantom: PhantomData,
32        }
33    }
34
35    /// Returns `true` if the [`Ptr`] is null.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// use sdd::Ptr;
41    ///
42    /// let ptr: Ptr<usize> = Ptr::null();
43    /// assert!(ptr.is_null());
44    /// ```
45    #[inline]
46    #[must_use]
47    pub fn is_null(&self) -> bool {
48        Tag::unset_tag(self.ptr).is_null()
49    }
50
51    /// Returns its [`Tag`].
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use sdd::{Ptr, Tag};
57    ///
58    /// let ptr: Ptr<usize> = Ptr::null();
59    /// assert_eq!(ptr.tag(), Tag::None);
60    /// ```
61    #[inline]
62    #[must_use]
63    pub fn tag(&self) -> Tag {
64        Tag::into_tag(self.ptr)
65    }
66
67    /// Sets a [`Tag`], overwriting its existing [`Tag`].
68    ///
69    /// Returns the previous tag value.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use sdd::{Ptr, Tag};
75    ///
76    /// let mut ptr: Ptr<usize> = Ptr::null();
77    /// assert_eq!(ptr.set_tag(Tag::Both), Tag::None);
78    /// assert_eq!(ptr.tag(), Tag::Both);
79    /// ```
80    #[inline]
81    pub fn set_tag(&mut self, tag: Tag) -> Tag {
82        let old_tag = Tag::into_tag(self.ptr);
83        self.ptr = Tag::update_tag(self.ptr, tag);
84        old_tag
85    }
86
87    /// Clears its [`Tag`].
88    ///
89    /// Returns the previous tag value.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use sdd::{Ptr, Tag};
95    ///
96    /// let mut ptr: Ptr<usize> = Ptr::null().with_tag(Tag::Both);
97    /// assert_eq!(ptr.unset_tag(), Tag::Both);
98    /// ```
99    #[inline]
100    pub fn unset_tag(&mut self) -> Tag {
101        let old_tag = Tag::into_tag(self.ptr);
102        self.ptr = Tag::unset_tag(self.ptr);
103        old_tag
104    }
105
106    /// Returns a copy of `self` with a [`Tag`] set.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use sdd::{Ptr, Tag};
112    ///
113    /// let mut ptr: Ptr<usize> = Ptr::null();
114    /// assert_eq!(ptr.tag(), Tag::None);
115    ///
116    /// let ptr_with_tag = ptr.with_tag(Tag::First);
117    /// assert_eq!(ptr_with_tag.tag(), Tag::First);
118    /// ```
119    #[inline]
120    #[must_use]
121    pub fn with_tag(self, tag: Tag) -> Self {
122        Self::from(Tag::update_tag(self.ptr, tag))
123    }
124
125    /// Returns a copy of `self` with its [`Tag`] erased.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use sdd::{Ptr, Tag};
131    ///
132    /// let mut ptr: Ptr<usize> = Ptr::null();
133    /// ptr.set_tag(Tag::Second);
134    /// assert_eq!(ptr.tag(), Tag::Second);
135    ///
136    /// let ptr_without_tag = ptr.without_tag();
137    /// assert_eq!(ptr_without_tag.tag(), Tag::None);
138    /// ```
139    #[inline]
140    #[must_use]
141    pub fn without_tag(self) -> Self {
142        Self::from(Tag::unset_tag(self.ptr))
143    }
144
145    /// Tries to create a reference to the underlying instance.
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// use sdd::{AtomicShared, Guard};
151    /// use std::sync::atomic::Ordering::Relaxed;
152    ///
153    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
154    /// let guard = Guard::new();
155    /// let ptr = atomic_shared.load(Relaxed, &guard);
156    /// assert_eq!(*ptr.as_ref().unwrap(), 21);
157    /// ```
158    #[inline]
159    #[must_use]
160    pub fn as_ref(&self) -> Option<&'g T> {
161        let ptr = Tag::unset_tag(self.ptr);
162        if ptr.is_null() {
163            return None;
164        }
165        unsafe { Some(&*ptr) }
166    }
167
168    /// Tries to create a reference to the underlying instance without checking tag bits.
169    ///
170    /// # Safety
171    ///
172    /// This [`Ptr`] must not have any tag bits set, otherwise dereferencing the pointer may lead to
173    /// undefined behavior.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// use sdd::{AtomicShared, Guard};
179    /// use std::sync::atomic::Ordering::Relaxed;
180    ///
181    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
182    /// let guard = Guard::new();
183    /// let ptr = atomic_shared.load(Relaxed, &guard);
184    /// assert_eq!(unsafe { *ptr.as_ref_unchecked().unwrap() }, 21);
185    /// ```
186    #[inline]
187    #[must_use]
188    pub const unsafe fn as_ref_unchecked(&self) -> Option<&'g T> {
189        unsafe { RefCounted::inst_ptr(self.ptr).as_ref() }
190    }
191
192    /// Provides a raw pointer to the instance.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use sdd::{Guard, Shared};
198    /// use std::sync::atomic::Ordering::Relaxed;
199    ///
200    /// let shared: Shared<usize> = Shared::new(29);
201    /// let guard = Guard::new();
202    /// let ptr = shared.get_guarded_ptr(&guard);
203    /// drop(shared);
204    ///
205    /// assert_eq!(unsafe { *ptr.as_ptr() }, 29);
206    /// ```
207    #[inline]
208    #[must_use]
209    pub fn as_ptr(&self) -> *const T {
210        RefCounted::inst_ptr(Tag::unset_tag(self.ptr))
211    }
212
213    /// Tries to create a pointer to the underlying instance without checking tag bits.
214    ///
215    /// # Safety
216    ///
217    /// This [`Ptr`] must not have any tag bits set, otherwise dereferencing the pointer may lead to
218    /// undefined behavior.
219    ///
220    /// # Examples
221    ///
222    /// ```
223    /// use sdd::{AtomicShared, Guard};
224    /// use std::sync::atomic::Ordering::Relaxed;
225    ///
226    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
227    /// let guard = Guard::new();
228    /// let ptr = atomic_shared.load(Relaxed, &guard);
229    /// assert_eq!(unsafe { *ptr.as_ptr_unchecked() }, 21);
230    /// ```
231    #[inline]
232    #[must_use]
233    pub const unsafe fn as_ptr_unchecked(&self) -> *const T {
234        RefCounted::inst_ptr(self.ptr)
235    }
236
237    /// Tries to convert itself into a [`Shared`].
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// use sdd::{Guard, Shared};
243    ///
244    /// let shared: Shared<usize> = Shared::new(83);
245    /// let guard = Guard::new();
246    /// let ptr = shared.get_guarded_ptr(&guard);
247    /// let shared_restored = ptr.get_shared().unwrap();
248    /// assert_eq!(*shared_restored, 83);
249    ///
250    /// drop(shared);
251    /// drop(shared_restored);
252    ///
253    /// assert!(ptr.get_shared().is_none());
254    /// ```
255    #[inline]
256    #[must_use]
257    pub fn get_shared(self) -> Option<Shared<T>> {
258        unsafe {
259            if let Some(ptr) = NonNull::new(Tag::unset_tag(self.ptr).cast_mut()) {
260                if (*ptr.as_ptr()).try_add_ref(Relaxed) {
261                    return Some(Shared::from(ptr));
262                }
263            }
264        }
265        None
266    }
267
268    /// Creates a new [`Ptr`] from a [`RefCounted`] pointer.
269    #[inline]
270    pub(super) const fn from(ptr: *const RefCounted<T>) -> Self {
271        Self {
272            ptr,
273            _phantom: PhantomData,
274        }
275    }
276
277    /// Returns a pointer to the [`RefCounted`], including tag bits.
278    #[inline]
279    pub(super) const fn underlying_ptr(self) -> *const RefCounted<T> {
280        self.ptr
281    }
282}
283
284impl<T> Clone for Ptr<'_, T> {
285    #[inline]
286    fn clone(&self) -> Self {
287        *self
288    }
289}
290
291impl<T> Copy for Ptr<'_, T> {}
292
293impl<T> Default for Ptr<'_, T> {
294    #[inline]
295    fn default() -> Self {
296        Self::null()
297    }
298}
299
300impl<T> Eq for Ptr<'_, T> {}
301
302impl<T> PartialEq for Ptr<'_, T> {
303    #[inline]
304    fn eq(&self, other: &Self) -> bool {
305        self.ptr == other.ptr
306    }
307}
308
309impl<T: UnwindSafe> UnwindSafe for Ptr<'_, T> {}