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> {}