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 crate::ref_counted::RefCounted;
7use crate::{Shared, Tag};
8
9/// [`Ptr`] points to an instance.
10#[derive(Debug)]
11pub struct Ptr<'g, T> {
12    instance_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            instance_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.instance_ptr).is_null()
49    }
50
51    /// Tries to create a reference to the underlying instance.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use sdd::{AtomicShared, Guard};
57    /// use std::sync::atomic::Ordering::Relaxed;
58    ///
59    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
60    /// let guard = Guard::new();
61    /// let ptr = atomic_shared.load(Relaxed, &guard);
62    /// assert_eq!(*ptr.as_ref().unwrap(), 21);
63    /// ```
64    #[inline]
65    #[must_use]
66    pub fn as_ref(&self) -> Option<&'g T> {
67        let ptr = Tag::unset_tag(self.instance_ptr);
68        if ptr.is_null() {
69            return None;
70        }
71        unsafe { Some(&*ptr) }
72    }
73
74    /// Tries to create a reference to the underlying instance without checking tag bits.
75    ///
76    /// # Safety
77    ///
78    /// This [`Ptr`] must not have any tag bits set, otherwise dereferencing the pointer may lead to
79    /// undefined behavior.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use sdd::{AtomicShared, Guard};
85    /// use std::sync::atomic::Ordering::Relaxed;
86    ///
87    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
88    /// let guard = Guard::new();
89    /// let ptr = atomic_shared.load(Relaxed, &guard);
90    /// assert_eq!(unsafe { *ptr.as_ref_unchecked().unwrap() }, 21);
91    /// ```
92    #[inline]
93    #[must_use]
94    pub const unsafe fn as_ref_unchecked(&self) -> Option<&'g T> {
95        unsafe { RefCounted::inst_ptr(self.instance_ptr).as_ref() }
96    }
97
98    /// Provides a raw pointer to the instance.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use sdd::{Guard, Shared};
104    /// use std::sync::atomic::Ordering::Relaxed;
105    ///
106    /// let shared: Shared<usize> = Shared::new(29);
107    /// let guard = Guard::new();
108    /// let ptr = shared.get_guarded_ptr(&guard);
109    /// drop(shared);
110    ///
111    /// assert_eq!(unsafe { *ptr.as_ptr() }, 29);
112    /// ```
113    #[inline]
114    #[must_use]
115    pub fn as_ptr(&self) -> *const T {
116        RefCounted::inst_ptr(Tag::unset_tag(self.instance_ptr))
117    }
118
119    /// Tries to create a pointer to the underlying instance without checking tag bits.
120    ///
121    /// # Safety
122    ///
123    /// This [`Ptr`] must not have any tag bits set, otherwise dereferencing the pointer may lead to
124    /// undefined behavior.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use sdd::{AtomicShared, Guard};
130    /// use std::sync::atomic::Ordering::Relaxed;
131    ///
132    /// let atomic_shared: AtomicShared<usize> = AtomicShared::new(21);
133    /// let guard = Guard::new();
134    /// let ptr = atomic_shared.load(Relaxed, &guard);
135    /// assert_eq!(unsafe { *ptr.as_ptr_unchecked() }, 21);
136    /// ```
137    #[inline]
138    #[must_use]
139    pub const unsafe fn as_ptr_unchecked(&self) -> *const T {
140        RefCounted::inst_ptr(self.instance_ptr)
141    }
142
143    /// Returns its [`Tag`].
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use sdd::{Ptr, Tag};
149    ///
150    /// let ptr: Ptr<usize> = Ptr::null();
151    /// assert_eq!(ptr.tag(), Tag::None);
152    /// ```
153    #[inline]
154    #[must_use]
155    pub fn tag(&self) -> Tag {
156        Tag::into_tag(self.instance_ptr)
157    }
158
159    /// Sets a [`Tag`], overwriting its existing [`Tag`].
160    ///
161    /// Returns the previous tag value.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use sdd::{Ptr, Tag};
167    ///
168    /// let mut ptr: Ptr<usize> = Ptr::null();
169    /// assert_eq!(ptr.set_tag(Tag::Both), Tag::None);
170    /// assert_eq!(ptr.tag(), Tag::Both);
171    /// ```
172    #[inline]
173    pub fn set_tag(&mut self, tag: Tag) -> Tag {
174        let old_tag = Tag::into_tag(self.instance_ptr);
175        self.instance_ptr = Tag::update_tag(self.instance_ptr, tag);
176        old_tag
177    }
178
179    /// Clears its [`Tag`].
180    ///
181    /// Returns the previous tag value.
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// use sdd::{Ptr, Tag};
187    ///
188    /// let mut ptr: Ptr<usize> = Ptr::null().with_tag(Tag::Both);
189    /// assert_eq!(ptr.unset_tag(), Tag::Both);
190    /// ```
191    #[inline]
192    pub fn unset_tag(&mut self) -> Tag {
193        let old_tag = Tag::into_tag(self.instance_ptr);
194        self.instance_ptr = Tag::unset_tag(self.instance_ptr);
195        old_tag
196    }
197
198    /// Returns a copy of `self` with a [`Tag`] set.
199    ///
200    /// # Examples
201    ///
202    /// ```
203    /// use sdd::{Ptr, Tag};
204    ///
205    /// let mut ptr: Ptr<usize> = Ptr::null();
206    /// assert_eq!(ptr.tag(), Tag::None);
207    ///
208    /// let ptr_with_tag = ptr.with_tag(Tag::First);
209    /// assert_eq!(ptr_with_tag.tag(), Tag::First);
210    /// ```
211    #[inline]
212    #[must_use]
213    pub fn with_tag(self, tag: Tag) -> Self {
214        Self::from(Tag::update_tag(self.instance_ptr, tag))
215    }
216
217    /// Returns a copy of `self` with its [`Tag`] erased.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// use sdd::{Ptr, Tag};
223    ///
224    /// let mut ptr: Ptr<usize> = Ptr::null();
225    /// ptr.set_tag(Tag::Second);
226    /// assert_eq!(ptr.tag(), Tag::Second);
227    ///
228    /// let ptr_without_tag = ptr.without_tag();
229    /// assert_eq!(ptr_without_tag.tag(), Tag::None);
230    /// ```
231    #[inline]
232    #[must_use]
233    pub fn without_tag(self) -> Self {
234        Self::from(Tag::unset_tag(self.instance_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.instance_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 raw pointer.
269    #[inline]
270    pub(super) const fn from(ptr: *const RefCounted<T>) -> Self {
271        Self {
272            instance_ptr: ptr,
273            _phantom: PhantomData,
274        }
275    }
276
277    /// Provides a raw pointer to its [`RefCounted`].
278    #[inline]
279    pub(super) const fn as_underlying_ptr(self) -> *const RefCounted<T> {
280        self.instance_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.instance_ptr == other.instance_ptr
306    }
307}
308
309impl<T: UnwindSafe> UnwindSafe for Ptr<'_, T> {}