shapely_opaque/lib.rs
1//! Opaque pointers
2//!
3//! TODO: should these carry a Layout around? That would be neat actually.
4
5use std::{marker::PhantomData, ptr::NonNull};
6
7/// A type-erased pointer to an uninitialized value
8#[derive(Clone, Copy)]
9pub struct OpaqueUninit<'mem>(*mut u8, PhantomData<&'mem mut ()>);
10
11impl<'mem> OpaqueUninit<'mem> {
12 /// Create a new opaque pointer from a mutable pointer
13 pub fn new<T>(ptr: *mut T) -> Self {
14 Self(ptr as *mut u8, PhantomData)
15 }
16
17 /// Creates a new opaque pointer from a reference to a MaybeUninit<T>
18 ///
19 /// The pointer will point to the potentially uninitialized contents
20 pub fn from_maybe_uninit<T>(borrow: &'mem mut std::mem::MaybeUninit<T>) -> Self {
21 Self(borrow.as_mut_ptr() as *mut u8, PhantomData)
22 }
23
24 /// Assumes the pointer is initialized and returns an `Opaque` pointer
25 ///
26 /// # Safety
27 ///
28 /// The pointer must actually be pointing to initialized memory of the correct type.
29 pub unsafe fn assume_init(self) -> Opaque<'mem> {
30 let ptr = unsafe { NonNull::new_unchecked(self.0) };
31 Opaque(ptr, PhantomData)
32 }
33
34 /// Write a value to this location and convert to an initialized pointer
35 ///
36 /// # Safety
37 ///
38 /// The pointer must be properly aligned for T and point to allocated memory
39 /// that can be safely written to.
40 pub unsafe fn write<T>(self, value: T) -> Opaque<'mem> {
41 unsafe {
42 std::ptr::write(self.0 as *mut T, value);
43 self.assume_init()
44 }
45 }
46
47 /// Returns the underlying raw pointer as a byte pointer
48 pub fn as_mut_ptr(self) -> *mut u8 {
49 self.0
50 }
51
52 /// Returns the underlying raw pointer as a const byte pointer
53 pub fn as_ptr(self) -> *const u8 {
54 self.0
55 }
56
57 /// Returns a pointer with the given offset added
58 ///
59 /// # Safety
60 ///
61 /// Offset is within the bounds of the allocated memory
62 pub unsafe fn field_uninit(self, offset: usize) -> OpaqueUninit<'mem> {
63 OpaqueUninit(unsafe { self.0.byte_add(offset) }, PhantomData)
64 }
65
66 /// Returns a pointer with the given offset added, assuming it's initialized
67 ///
68 /// # Safety
69 ///
70 /// The pointer plus offset must be:
71 /// - Within bounds of the allocated object
72 /// - Properly aligned for the type being pointed to
73 /// - Point to initialized data of the correct type
74 pub unsafe fn field_init(self, offset: usize) -> Opaque<'mem> {
75 Opaque(
76 unsafe { NonNull::new_unchecked(self.0.add(offset)) },
77 PhantomData,
78 )
79 }
80}
81
82/// A type-erased read-only pointer to an initialized value.
83///
84/// Cannot be null. May be dangling (for ZSTs)
85#[derive(Clone, Copy)]
86pub struct OpaqueConst<'mem>(NonNull<u8>, PhantomData<&'mem ()>);
87
88impl<'mem> OpaqueConst<'mem> {
89 /// Create a new opaque const pointer from a reference
90 pub fn from_ref<T>(r: &'mem T) -> Self {
91 Self(NonNull::from(r).cast(), PhantomData)
92 }
93
94 /// Create a new opaque const pointer from a raw pointer
95 ///
96 /// # Safety
97 ///
98 /// The pointer must be valid, aligned, and point to initialized memory
99 /// of the correct type, and be valid for lifetime `'mem`.
100 pub unsafe fn new_unchecked<T>(ptr: *const T) -> Self {
101 unsafe { Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData) }
102 }
103
104 /// Gets the underlying raw pointer as a byte pointer
105 pub fn as_byte_ptr(self) -> *const u8 {
106 self.0.as_ptr()
107 }
108
109 /// Gets the underlying raw pointer as a pointer of type T
110 ///
111 /// # Safety
112 ///
113 /// Must be called with the original type T that was used to create this pointer
114 pub unsafe fn as_ptr<T>(self) -> *const T {
115 self.0.as_ptr() as *const T
116 }
117
118 /// Gets the underlying raw pointer as a const pointer of type T
119 ///
120 /// # Safety
121 ///
122 /// `T` must be the _actual_ underlying type. You're downcasting with no guardrails.
123 pub unsafe fn as_ref<'borrow: 'mem, T>(self) -> &'borrow T {
124 unsafe { &*(self.0.as_ptr() as *const T) }
125 }
126
127 /// Returns a pointer with the given offset added
128 ///
129 /// # Safety
130 ///
131 /// Offset must be within the bounds of the allocated memory,
132 /// and the resulting pointer must be properly aligned.
133 pub unsafe fn field(self, offset: usize) -> OpaqueConst<'mem> {
134 OpaqueConst(
135 unsafe { NonNull::new_unchecked(self.0.as_ptr().byte_add(offset)) },
136 PhantomData,
137 )
138 }
139}
140
141/// A type-erased pointer to an initialized value
142#[derive(Clone, Copy)]
143pub struct Opaque<'mem>(NonNull<u8>, PhantomData<&'mem mut ()>);
144
145impl<'mem> Opaque<'mem> {
146 /// Create a new opaque pointer from a mutable reference
147 pub fn from_ref<T>(r: &'mem mut T) -> Self {
148 Self(NonNull::from(r).cast(), PhantomData)
149 }
150
151 /// Create a new opaque pointer from a raw pointer
152 ///
153 /// # Safety
154 ///
155 /// The pointer must be valid, aligned, and point to initialized memory
156 /// of the correct type, and be valid for lifetime `'mem`.
157 pub unsafe fn new_unchecked<T>(ptr: *mut T) -> Self {
158 Self(
159 unsafe { NonNull::new_unchecked(ptr as *mut u8) },
160 PhantomData,
161 )
162 }
163
164 /// Gets the underlying raw pointer
165 pub fn as_byte_ptr(self) -> *const u8 {
166 self.0.as_ptr()
167 }
168
169 /// Gets the underlying raw pointer as mutable
170 pub fn as_mut_byte_ptr(self) -> *mut u8 {
171 self.0.as_ptr()
172 }
173
174 /// Gets the underlying raw pointer as a pointer of type T
175 ///
176 /// # Safety
177 ///
178 /// Must be called with the original type T that was used to create this pointer
179 pub unsafe fn as_ptr<T>(self) -> *const T {
180 self.0.as_ptr() as *const T
181 }
182
183 /// Gets the underlying raw pointer as a mutable pointer of type T
184 ///
185 /// # Safety
186 ///
187 /// `T` must be the _actual_ iunderlying type. You're downcasting with no guardrails.
188 pub unsafe fn as_mut_ptr<'borrow: 'mem, T>(self) -> &'borrow mut T {
189 unsafe { &mut *(self.0.as_ptr() as *mut T) }
190 }
191
192 /// Gets the underlying raw pointer as a const pointer of type T
193 ///
194 /// # Safety
195 ///
196 /// `T` must be the _actual_ underlying type. You're downcasting with no guardrails.
197 pub unsafe fn as_ref<'borrow: 'mem, T>(self) -> &'borrow T {
198 unsafe { &*(self.0.as_ptr() as *const T) }
199 }
200
201 /// Make a const ptr out of this mut ptr
202 pub fn as_const<'borrow: 'mem>(self) -> OpaqueConst<'borrow> {
203 OpaqueConst(self.0, PhantomData)
204 }
205
206 /// Exposes [`std::ptr::read`]
207 ///
208 /// # Safety
209 ///
210 /// `T` must be the actual underlying type of the pointed-to memory.
211 /// The memory must be properly initialized and aligned for type `T`.
212 pub unsafe fn read<T>(self) -> T {
213 unsafe { std::ptr::read(self.as_mut_ptr()) }
214 }
215
216 /// Exposes [`std::ptr::drop_in_place`]
217 ///
218 /// # Safety
219 ///
220 /// `T` must be the actual underlying type of the pointed-to memory.
221 /// The memory must be properly initialized and aligned for type `T`.
222 /// After calling this function, the memory should not be accessed again
223 /// until it is properly reinitialized.
224 pub unsafe fn drop_in_place<T>(self) {
225 unsafe { std::ptr::drop_in_place(self.as_mut_ptr::<T>()) }
226 }
227}