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