flize/
shared.rs

1use crate::tag::{read_tag, set_tag, strip, NullTag, Tag, TagPosition};
2use core::fmt::{self, Debug};
3use core::marker::PhantomData;
4use core::ptr;
5
6/// A `Shared` represents a tagged pointer.
7/// It provides various utility methods for type conversion
8/// and tag manipulation. In addition it is the only pointer type
9/// that can be used to interact with `Atomic` since this type
10/// enforces a lifetime based on the shield used to create it.
11#[repr(transparent)]
12pub struct Shared<'shield, V, T1 = NullTag, T2 = NullTag>
13where
14    V: 'shield,
15    T1: Tag,
16    T2: Tag,
17{
18    pub(crate) data: usize,
19    _m0: PhantomData<&'shield ()>,
20    _m1: PhantomData<V>,
21    _m2: PhantomData<T1>,
22    _m3: PhantomData<T2>,
23}
24
25impl<'shield, V, T1, T2> Shared<'shield, V, T1, T2>
26where
27    V: 'shield,
28    T1: Tag,
29    T2: Tag,
30{
31    pub fn null() -> Self {
32        unsafe { Self::from_raw(ptr::null::<()>() as usize) }
33    }
34
35    /// Constructs a `Shared` from a raw tagged pointer with an arbitrary lifetime.
36    ///
37    /// # Safety
38    /// The alignment of `V` must free up sufficient low bits so that `T` fits.
39    pub unsafe fn from_ptr(ptr: *mut V) -> Self {
40        Self::from_raw(ptr as usize)
41    }
42
43    /// Constructs a `Shared` from a raw tagged pointer represented as an integer with an arbitrary lifetime.
44    ///
45    /// This function constructs a `Shared<'shield, V, T>` from a raw tagged pointer.
46    ///
47    /// # Safety
48    /// This is marked unsafe because extreme caution must be taken to
49    /// supply correct data and ensure the lifetime is what you expect.
50    pub unsafe fn from_raw(data: usize) -> Self {
51        Self {
52            data,
53            _m0: PhantomData,
54            _m1: PhantomData,
55            _m2: PhantomData,
56            _m3: PhantomData,
57        }
58    }
59
60    /// Get the raw tagged pointer as an integer.
61    pub fn into_raw(self) -> usize {
62        self.data
63    }
64
65    /// Get the raw tagged pointer.
66    pub fn as_ptr(self) -> *mut V {
67        self.data as *mut V
68    }
69
70    /// Remove all tags by zeroing their bits.
71    pub fn strip(self) -> Self {
72        let data = strip::<T1, T2>(self.data);
73        unsafe { Self::from_raw(data) }
74    }
75
76    /// Converts the pointer into a reference.
77    /// This will panic if the tagged pointer is null.
78    ///
79    /// # Safety
80    /// - The pointer must either be null or point to a valid instance of `V`.
81    /// - You must ensure the instance of `V` is not borrowed mutably.
82    pub unsafe fn as_ref(self) -> Option<&'shield V> {
83        self.as_ptr().as_ref()
84    }
85
86    /// Converts the pointer into a mutable reference.
87    /// This will panic if the tagged pointer is null.
88    ///
89    /// # Safety
90    /// - The pointer must either be null or point to a valid instance of `V`.
91    /// - You must ensure the instance of `V` is not borrowed.
92    pub unsafe fn as_mut_ref(self) -> Option<&'shield mut V> {
93        let ptr = self.as_ptr();
94
95        if !ptr.is_null() {
96            Some(&mut *ptr)
97        } else {
98            None
99        }
100    }
101
102    /// Converts the pointer into a reference.
103    ///
104    /// # Safety
105    /// - The pointer must point to a valid instance of `V`.
106    /// - You must ensure the instance of `V` is not borrowed mutably.
107    pub unsafe fn as_ref_unchecked(self) -> &'shield V {
108        &*self.as_ptr()
109    }
110
111    /// Converts the pointer into a mutable reference.
112    ///
113    /// # Safety
114    /// - The pointer must point to a valid instance of `V`.
115    /// - You must ensure the instance of `V` is not borrowed.
116    pub unsafe fn as_mut_ref_unchecked(self) -> &'shield mut V {
117        &mut *self.as_ptr()
118    }
119
120    /// Check if the tagged pointer is null.
121    pub fn is_null(self) -> bool {
122        self.as_ptr().is_null()
123    }
124
125    /// Get the tag in the low position.
126    pub fn tag_lo(self) -> T1 {
127        let bits = read_tag::<T1>(self.data, TagPosition::Lo);
128        Tag::deserialize(bits)
129    }
130
131    /// Get the tag in the high position.
132    pub fn tag_hi(self) -> T2 {
133        let bits = read_tag::<T2>(self.data, TagPosition::Hi);
134        Tag::deserialize(bits)
135    }
136
137    /// Set the tag in the low position.
138    pub fn with_tag_lo(self, tag: T1) -> Self {
139        let bits = tag.serialize();
140        let data = set_tag::<T1>(self.data, bits, TagPosition::Lo);
141        unsafe { Self::from_raw(data) }
142    }
143
144    /// Set the tag in the high position.
145    pub fn with_tag_hi(self, tag: T2) -> Self {
146        let bits = tag.serialize();
147        let data = set_tag::<T2>(self.data, bits, TagPosition::Hi);
148        unsafe { Self::from_raw(data) }
149    }
150}
151
152impl<'shield, V, T1, T2> Clone for Shared<'shield, V, T1, T2>
153where
154    V: 'shield,
155    T1: Tag,
156    T2: Tag,
157{
158    fn clone(&self) -> Self {
159        unsafe { Self::from_raw(self.data) }
160    }
161}
162
163impl<'shield, V, T1, T2> Copy for Shared<'shield, V, T1, T2>
164where
165    V: 'shield,
166    T1: Tag,
167    T2: Tag,
168{
169}
170
171impl<'shield, V, T1, T2> PartialEq for Shared<'shield, V, T1, T2>
172where
173    V: 'shield,
174    T1: Tag,
175    T2: Tag,
176{
177    fn eq(&self, other: &Self) -> bool {
178        self.into_raw() == other.into_raw()
179    }
180}
181
182impl<'shield, V, T1, T2> Eq for Shared<'shield, V, T1, T2>
183where
184    V: 'shield,
185    T1: Tag,
186    T2: Tag,
187{
188}
189
190impl<'shield, V, T1, T2> Debug for Shared<'shield, V, T1, T2>
191where
192    V: 'shield,
193    T1: Tag,
194    T2: Tag,
195{
196    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
197        write!(formatter, "{:?}", self.data)
198    }
199}
200
201unsafe impl<'shield, V, T1, T2> Send for Shared<'shield, V, T1, T2>
202where
203    V: 'shield,
204    T1: Tag,
205    T2: Tag,
206{
207}
208
209unsafe impl<'shield, V, T1, T2> Sync for Shared<'shield, V, T1, T2>
210where
211    V: 'shield,
212    T1: Tag,
213    T2: Tag,
214{
215}
216
217impl<'shield, V, T1, T2> Unpin for Shared<'shield, V, T1, T2>
218where
219    V: 'shield,
220    T1: Tag,
221    T2: Tag,
222{
223}