xref: /relibc/ralloc/src/ptr.rs (revision cccbe11957ca18dd484a8d88987950f143d56680)
1 //! Pointer wrappers.
2 
3 use core::ptr::NonNull;
4 use core::marker;
5 
6 /// A pointer wrapper type.
7 ///
8 /// A wrapper around a raw non-null `*mut T` that indicates that the possessor of this wrapper owns
9 /// the referent.
10 #[derive(PartialEq, Eq, Debug, Clone)]
11 pub struct Pointer<T> {
12     /// The internal pointer.
13     ptr: NonNull<T>,
14     /// Associated phantom data.
15     ///
16     /// This indicates that we _own_ T.
17     _phantom: marker::PhantomData<T>,
18 }
19 
20 impl<T> Pointer<T> {
21     /// Create a new `Pointer` from a raw pointer.
22     ///
23     /// # Safety
24     ///
25     /// This function is unsafe since a null pointer can cause UB, due to `Pointer` being
26     /// non-nullable.
27     #[inline]
28     pub unsafe fn new(ptr: *mut T) -> Pointer<T> {
29         // For the sake of nice debugging, make some assertions.
30         debug_assert!(!ptr.is_null(), "Null pointer!");
31 
32         Pointer {
33             ptr: NonNull::new_unchecked(ptr),
34             _phantom: marker::PhantomData,
35         }
36     }
37 
38     /// Create an "empty" `Pointer`.
39     ///
40     /// This acts as a null pointer, although it is represented by 0x1 instead of 0x0.
41     #[inline]
42     pub const fn empty() -> Pointer<T> {
43         Pointer {
44             ptr: unsafe {
45                 // LAST AUDIT: 2016-08-21 (Ticki).
46 
47                 // 0x1 is non-zero.
48                 NonNull::new_unchecked(0x1 as *mut T)
49             },
50             _phantom: marker::PhantomData,
51         }
52     }
53 
54     /// Cast this pointer into a pointer to another type.
55     ///
56     /// This will simply transmute the pointer, leaving the actual data unmodified.
57     #[inline]
58     pub fn cast<U>(self) -> Pointer<U> {
59         Pointer {
60             ptr: unsafe {
61                 // LAST AUDIT: 2016-08-21 (Ticki).
62 
63                 // Casting the pointer will preserve its nullable state.
64                 NonNull::new_unchecked(self.get() as *mut U)
65             },
66             _phantom: marker::PhantomData,
67         }
68     }
69 
70     /// Offset this pointer.
71     ///
72     /// This will add some value multiplied by the size of T to the pointer.
73     ///
74     /// # Safety
75     ///
76     /// This is unsafe, due to OOB offsets being undefined behavior.
77     #[inline]
78     pub unsafe fn offset(self, diff: isize) -> Pointer<T> {
79         Pointer::new(self.ptr.as_ptr().offset(diff))
80     }
81 
82     pub fn get(&self) -> *mut T {
83         self.ptr.as_ptr()
84     }
85 }
86 
87 impl<T> Default for Pointer<T> {
88     fn default() -> Pointer<T> {
89         Pointer::empty()
90     }
91 }
92 
93 unsafe impl<T: Send> Send for Pointer<T> {}
94 unsafe impl<T: Sync> Sync for Pointer<T> {}
95 
96 #[cfg(test)]
97 mod test {
98     use super::*;
99 
100     #[test]
101     fn test_pointer() {
102         let mut x = [b'a', b'b'];
103 
104         unsafe {
105             let ptr = Pointer::new(&mut x[0] as *mut u8);
106             assert_eq!(*ptr.get(), b'a');
107             assert_eq!(*ptr.clone().cast::<[u8; 1]>().get(), [b'a']);
108             assert_eq!(*ptr.offset(1).get(), b'b');
109         }
110 
111         let mut y = ['a', 'b'];
112 
113         unsafe {
114             let ptr = Pointer::new(&mut y[0] as *mut char);
115             assert_eq!(*ptr.clone().cast::<[char; 1]>().get(), ['a']);
116             assert_eq!(*ptr.offset(1).get(), 'b');
117         }
118     }
119 
120     #[test]
121     fn test_empty() {
122         assert_eq!(Pointer::<u8>::empty().get() as usize, 1);
123     }
124 }
125