1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
use core::cmp::{self, PartialEq, PartialOrd};
use core::fmt;
use core::marker::PhantomData;
use core::ptr::{self, NonNull};

use typenum::{IsGreaterOrEqual, True, Unsigned};

use crate::pointer::{self, MarkedNonNull, MarkedPtr};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Copy & Clone
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N> Clone for MarkedPtr<T, N> {
    #[inline]
    fn clone(&self) -> Self {
        Self::new(self.inner)
    }
}

impl<T, N> Copy for MarkedPtr<T, N> {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// inherent (const)
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N> MarkedPtr<T, N> {
    /// Creates an unmarked pointer.
    #[inline]
    pub const fn new(ptr: *mut T) -> Self {
        Self { inner: ptr, _marker: PhantomData }
    }

    /// Creates a new & unmarked `null` pointer.
    #[inline]
    pub const fn null() -> Self {
        Self::new(ptr::null_mut())
    }

    /// Cast to a pointer of another type.
    #[inline]
    pub const fn cast<U>(self) -> MarkedPtr<U, N> {
        MarkedPtr::new(self.inner as *mut U)
    }

    /// Creates a marked pointer from the numeric representation of a
    /// potentially marked pointer.
    #[inline]
    pub const fn from_usize(val: usize) -> Self {
        Self::new(val as *mut _)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// inherent
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N: Unsigned> MarkedPtr<T, N> {
    /// The number of available mark bits for this type.
    pub const MARK_BITS: usize = N::USIZE;
    /// The bitmask for the lower markable bits.
    pub const MARK_MASK: usize = pointer::mark_mask::<T>(Self::MARK_BITS);
    /// The bitmask for the higher pointer bits.
    pub const POINTER_MASK: usize = !Self::MARK_MASK;

    /// Returns the numeric representation of the pointer with its tag.
    #[inline]
    pub fn into_usize(self) -> usize {
        self.inner as usize
    }

    /// Returns the inner pointer *as is*, meaning potential tags are not
    /// stripped.
    #[inline]
    pub fn into_ptr(self) -> *mut T {
        self.inner
    }

    /// Composes a new marked pointer from a raw unmarked pointer and a tag
    /// value.
    #[inline]
    pub fn compose(ptr: *mut T, tag: usize) -> Self {
        debug_assert_eq!(0, ptr as usize & Self::MARK_MASK, "pointer must be properly aligned");
        Self::new(pointer::compose::<_, N>(ptr, tag))
    }

    /// Converts a marked pointer with `M` potential mark bits to the **same**
    /// marked pointer with `N` potential mark bits, requires that `N >= M`.
    #[inline]
    pub fn convert<M: Unsigned>(other: MarkedPtr<T, M>) -> Self
    where
        N: IsGreaterOrEqual<M, Output = True>,
    {
        Self::new(other.inner)
    }

    /// Clears the tag of `self` and returns the same but untagged pointer.
    #[inline]
    pub fn clear_tag(self) -> Self {
        Self::new(self.decompose_ptr())
    }

    /// Clears the tag of `self` and replaces it with `tag`.
    #[inline]
    pub fn with_tag(self, tag: usize) -> Self {
        Self::compose(self.decompose_ptr(), tag)
    }

    /// Decomposes the marked pointer, returning the separated raw pointer and
    /// its tag.
    #[inline]
    pub fn decompose(self) -> (*mut T, usize) {
        pointer::decompose(self.into_usize(), Self::MARK_BITS)
    }

    /// Decomposes the marked pointer, returning only the separated raw pointer.
    #[inline]
    pub fn decompose_ptr(self) -> *mut T {
        pointer::decompose_ptr(self.into_usize(), Self::MARK_BITS)
    }

    /// Decomposes the marked pointer, returning only the separated tag.
    #[inline]
    pub fn decompose_tag(self) -> usize {
        pointer::decompose_tag::<T>(self.into_usize(), Self::MARK_BITS)
    }

    /// Decomposes the marked pointer, returning an optional reference and the
    /// separated tag.
    ///
    /// In case the pointer stripped of its tag is null, [`None`] is returned as
    /// part of the tuple. Otherwise, the reference is wrapped in a [`Some`].
    ///
    /// # Safety
    ///
    /// While this method and its mutable counterpart are useful for
    /// null-safety, it is important to note that this is still an unsafe
    /// operation because the returned value could be pointing to invalid
    /// memory.
    ///
    /// Additionally, the lifetime 'a returned is arbitrarily chosen and does
    /// not necessarily reflect the actual lifetime of the data.
    #[inline]
    pub unsafe fn decompose_ref<'a>(self) -> (Option<&'a T>, usize) {
        let (ptr, tag) = self.decompose();
        (ptr.as_ref(), tag)
    }

    /// Decomposes the marked pointer returning an optional mutable reference
    /// and the separated tag.
    ///
    /// In case the pointer stripped of its tag is null, [`None`] is returned as
    /// part of the tuple. Otherwise, the mutable reference is wrapped in a
    /// [`Some`].
    ///
    /// # Safety
    ///
    /// As with [`decompose_ref`][MarkedPtr::decompose_ref], this is unsafe
    /// because it cannot verify the validity of the returned pointer, nor can
    /// it ensure that the lifetime `'a` returned is indeed a valid lifetime for
    /// the contained data.
    #[inline]
    pub unsafe fn decompose_mut<'a>(self) -> (Option<&'a mut T>, usize) {
        let (ptr, tag) = self.decompose();
        (ptr.as_mut(), tag)
    }

    /// Decomposes the marked pointer, returning an optional reference and
    /// discarding the tag.
    ///
    /// # Safety
    ///
    /// The same caveats as with [`decompose_ref`][MarkedPtr::decompose_ref]
    /// apply for this method as well.
    #[inline]
    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
        self.decompose_ptr().as_ref()
    }

    /// Decomposes the marked pointer, returning an optional mutable reference
    /// and discarding the tag.
    ///
    /// # Safety
    ///
    /// The same caveats as with [`decompose_mut`][MarkedPtr::decompose_mut]
    /// apply for this method as well.
    #[inline]
    pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
        self.decompose_ptr().as_mut()
    }

    /// Returns true if the pointer is `null` (regardless of the tag).
    #[inline]
    pub fn is_null(self) -> bool {
        self.decompose_ptr().is_null()
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Default
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N: Unsigned> Default for MarkedPtr<T, N> {
    #[inline]
    fn default() -> Self {
        Self::null()
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Debug & Pointer (fmt)
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N: Unsigned> fmt::Debug for MarkedPtr<T, N> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (ptr, tag) = self.decompose();
        f.debug_struct("MarkedPtr").field("ptr", &ptr).field("tag", &tag).finish()
    }
}

impl<T, N: Unsigned> fmt::Pointer for MarkedPtr<T, N> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&self.decompose_ptr(), f)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// From
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N: Unsigned> From<*const T> for MarkedPtr<T, N> {
    #[inline]
    fn from(ptr: *const T) -> Self {
        Self::new(ptr as *mut _)
    }
}

impl<T, N: Unsigned> From<*mut T> for MarkedPtr<T, N> {
    fn from(ptr: *mut T) -> Self {
        Self::new(ptr)
    }
}

impl<'a, T, N: Unsigned> From<&'a T> for MarkedPtr<T, N> {
    #[inline]
    fn from(reference: &'a T) -> Self {
        Self::new(reference as *const _ as *mut _)
    }
}

impl<'a, T, N: Unsigned> From<&'a mut T> for MarkedPtr<T, N> {
    #[inline]
    fn from(reference: &'a mut T) -> Self {
        Self::new(reference)
    }
}

impl<T, N: Unsigned> From<NonNull<T>> for MarkedPtr<T, N> {
    #[inline]
    fn from(ptr: NonNull<T>) -> Self {
        Self::new(ptr.as_ptr())
    }
}

impl<T, N: Unsigned> From<(*mut T, usize)> for MarkedPtr<T, N> {
    #[inline]
    fn from(pair: (*mut T, usize)) -> Self {
        let (ptr, tag) = pair;
        Self::compose(ptr, tag)
    }
}

impl<T, N: Unsigned> From<(*const T, usize)> for MarkedPtr<T, N> {
    #[inline]
    fn from(pair: (*const T, usize)) -> Self {
        let (ptr, tag) = pair;
        Self::compose(ptr as *mut _, tag)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// PartialEq & PartialOrd
////////////////////////////////////////////////////////////////////////////////////////////////////

impl<T, N> PartialEq for MarkedPtr<T, N> {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.inner == other.inner
    }
}

impl<T, N> PartialOrd for MarkedPtr<T, N> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.inner.partial_cmp(&other.inner)
    }
}

impl<T, N> PartialEq<MarkedNonNull<T, N>> for MarkedPtr<T, N> {
    #[inline]
    fn eq(&self, other: &MarkedNonNull<T, N>) -> bool {
        self.inner.eq(&other.inner.as_ptr())
    }
}

impl<T, N> PartialOrd<MarkedNonNull<T, N>> for MarkedPtr<T, N> {
    #[inline]
    fn partial_cmp(&self, other: &MarkedNonNull<T, N>) -> Option<cmp::Ordering> {
        self.inner.partial_cmp(&other.inner.as_ptr())
    }
}

#[cfg(test)]
mod test {
    use core::ptr;

    use matches::assert_matches;
    use typenum::{U0, U1, U3};

    use crate::align::Aligned8;

    type UnmarkedMarkedPtr = super::MarkedPtr<Aligned8<i32>, U0>;
    type MarkedPtr1N = super::MarkedPtr<Aligned8<i32>, U1>;
    type MarkedPtr3N = super::MarkedPtr<Aligned8<i32>, U3>;

    #[test]
    fn decompose_ref() {
        let null = MarkedPtr3N::null();
        assert_eq!((None, 0), unsafe { null.decompose_ref() });

        let marked_null = MarkedPtr3N::compose(ptr::null_mut(), 0b111);
        assert_eq!((None, 0b111), unsafe { marked_null.decompose_ref() });

        let value = Aligned8(1);
        let marked = MarkedPtr3N::compose(&value as *const Aligned8<i32> as *mut _, 0b11);
        assert_eq!((Some(&value), 0b11), unsafe { marked.decompose_ref() });
    }

    #[test]
    fn decompose_mut() {
        let null = MarkedPtr3N::null();
        assert_eq!((None, 0), unsafe { null.decompose_mut() });

        let marked_null = MarkedPtr3N::compose(ptr::null_mut(), 0b111);
        assert_eq!((None, 0b111), unsafe { marked_null.decompose_mut() });

        let mut value = Aligned8(1);
        let marked = MarkedPtr3N::compose(&mut value, 0b11);
        assert_eq!((Some(&mut value), 0b11), unsafe { marked.decompose_mut() });
    }

    #[test]
    fn from_usize() {
        unsafe {
            let unmarked = UnmarkedMarkedPtr::from_usize(&Aligned8(1) as *const _ as usize);
            assert_matches!(unmarked.as_ref(), Some(&Aligned8(1)));

            let tagged = (&Aligned8(1i32) as *const _ as usize) | 0b1;
            assert_eq!(
                (Some(&Aligned8(1i32)), 0b1),
                MarkedPtr1N::from_usize(tagged).decompose_ref()
            );
        }
    }

    #[test]
    fn from() {
        let mut x = Aligned8(1);

        let from_ref = MarkedPtr1N::from(&x);
        let from_mut = MarkedPtr1N::from(&mut x);
        let from_const_ptr = MarkedPtr1N::from(&x as *const _);
        let from_mut_ptr = MarkedPtr1N::from(&mut x as *mut _);

        assert!(from_ref == from_mut && from_const_ptr == from_mut_ptr);
    }

    #[test]
    fn eq_ord() {
        let null = MarkedPtr3N::null();
        assert!(null.is_null());
        assert_eq!(null, null);

        let mut aligned = Aligned8(1);
        let marked1 = MarkedPtr3N::compose(&mut aligned, 0b01);
        let marked2 = MarkedPtr3N::compose(&mut aligned, 0b11);

        assert_ne!(marked1, marked2);
        assert!(marked1 < marked2);
    }

    #[test]
    fn convert() {
        let mut aligned = Aligned8(1);

        let marked = MarkedPtr1N::compose(&mut aligned, 0b1);
        let convert = MarkedPtr3N::convert(marked);

        assert_eq!((Some(&aligned), 0b1), unsafe { convert.decompose_ref() });
    }
}