facet_core/opaque/
mod.rs

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