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}