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}