• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 14459841398

15 Apr 2025 02:20AM UTC coverage: 30.835% (+0.7%) from 30.122%
14459841398

push

github

web-flow
Rename opaque to ptr, closes #221 (#222)

47 of 344 new or added lines in 20 files covered. (13.66%)

1 existing line in 1 file now uncovered.

2032 of 6590 relevant lines covered (30.83%)

25.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.14
/facet-core/src/ptr.rs
1
//! Opaque pointers
2
//!
3
//! Type-erased pointer helpers for working with reflected values
4

5
use core::{marker::PhantomData, ptr::NonNull};
6

7
/// A type-erased pointer to an uninitialized value
8
#[derive(Debug, Clone, Copy)]
9
pub struct PtrUninit<'mem>(*mut u8, PhantomData<&'mem mut ()>);
10

11
impl<'mem> PtrUninit<'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 {
214✔
16
        Self(ptr as *mut u8, PhantomData)
214✔
17
    }
18

19
    /// Creates a new opaque pointer from a reference to a [`core::mem::MaybeUninit`]
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) -> PtrMut<'mem> {
323✔
34
        let ptr = unsafe { NonNull::new_unchecked(self.0) };
323✔
35
        PtrMut(ptr, PhantomData)
323✔
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 put<T>(self, value: T) -> PtrMut<'mem> {
208✔
45
        unsafe {
46
            core::ptr::write(self.0 as *mut T, value);
208✔
47
            self.assume_init()
208✔
48
        }
49
    }
50

51
    /// Returns the underlying raw pointer as a byte pointer
52
    pub fn as_mut_byte_ptr(self) -> *mut u8 {
269✔
53
        self.0
269✔
54
    }
55

56
    /// Returns the underlying raw pointer as a const byte pointer
57
    pub fn as_byte_ptr(self) -> *const u8 {
560✔
58
        self.0
560✔
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_at(self, offset: usize) -> PtrUninit<'mem> {
170✔
67
        PtrUninit(unsafe { self.0.byte_add(offset) }, PhantomData)
170✔
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
NEW
78
    pub unsafe fn field_init(self, offset: usize) -> PtrMut<'mem> {
×
79
        PtrMut(
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, Debug, PartialEq, Eq, Hash)]
90
pub struct PtrConst<'mem>(NonNull<u8>, PhantomData<&'mem ()>);
91

92
unsafe impl Send for PtrConst<'_> {}
93
unsafe impl Sync for PtrConst<'_> {}
94

95
impl<'mem> PtrConst<'mem> {
96
    /// Create a new opaque const pointer from a raw pointer
97
    ///
98
    /// # Safety
99
    ///
100
    /// The pointer must be non-null, valid, aligned, and point to initialized memory
101
    /// of the correct type, and be valid for lifetime `'mem`.
102
    ///
103
    /// It's encouraged to take the address of something with `&raw const x`, rather than `&x`
104
    pub const fn new<T>(ptr: *const T) -> Self {
789✔
105
        unsafe { Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData) }
789✔
106
    }
107

108
    /// Gets the underlying raw pointer as a byte pointer
109
    pub const fn as_byte_ptr(self) -> *const u8 {
106✔
110
        self.0.as_ptr()
106✔
111
    }
112

113
    /// Gets the underlying raw pointer as a pointer of type T
114
    ///
115
    /// # Safety
116
    ///
117
    /// Must be called with the original type T that was used to create this pointer
118
    pub const unsafe fn as_ptr<T>(self) -> *const T {
89✔
119
        self.0.as_ptr() as *const T
89✔
120
    }
121

122
    /// Gets the underlying raw pointer as a const pointer of type T
123
    ///
124
    /// # Safety
125
    ///
126
    /// `T` must be the _actual_ underlying type. You're downcasting with no guardrails.
127
    pub const unsafe fn get<'borrow: 'mem, T>(self) -> &'borrow T {
1,085✔
128
        // TODO: rename to `get`, or something else? it's technically a borrow...
129
        unsafe { &*(self.0.as_ptr() as *const T) }
1,085✔
130
    }
131

132
    /// Returns a pointer with the given offset added
133
    ///
134
    /// # Safety
135
    ///
136
    /// Offset must be within the bounds of the allocated memory,
137
    /// and the resulting pointer must be properly aligned.
138
    pub const unsafe fn field(self, offset: usize) -> PtrConst<'mem> {
70✔
139
        PtrConst(
140
            unsafe { NonNull::new_unchecked(self.0.as_ptr().byte_add(offset)) },
70✔
141
            PhantomData,
70✔
142
        )
143
    }
144

145
    /// Exposes [`core::ptr::read`]
146
    ///
147
    /// # Safety
148
    ///
149
    /// `T` must be the actual underlying type of the pointed-to memory.
150
    /// The memory must be properly initialized and aligned for type `T`.
151
    pub const unsafe fn read<T>(self) -> T {
89✔
152
        unsafe { core::ptr::read(self.as_ptr()) }
89✔
153
    }
154
}
155

156
/// A type-erased pointer to an initialized value
157
#[derive(Clone, Copy)]
158
pub struct PtrMut<'mem>(NonNull<u8>, PhantomData<&'mem mut ()>);
159

160
impl<'mem> PtrMut<'mem> {
161
    /// Create a new opaque pointer from a raw pointer
162
    ///
163
    /// # Safety
164
    ///
165
    /// The pointer must be valid, aligned, and point to initialized memory
166
    /// of the correct type, and be valid for lifetime `'mem`.
167
    ///
168
    /// It's encouraged to take the address of something with `&raw mut x`, rather than `&x`
169
    pub const fn new<T>(ptr: *mut T) -> Self {
136✔
170
        Self(
171
            unsafe { NonNull::new_unchecked(ptr as *mut u8) },
136✔
172
            PhantomData,
136✔
173
        )
174
    }
175

176
    /// Gets the underlying raw pointer
177
    pub const fn as_byte_ptr(self) -> *const u8 {
2✔
178
        self.0.as_ptr()
2✔
179
    }
180

181
    /// Gets the underlying raw pointer as mutable
182
    pub const fn as_mut_byte_ptr(self) -> *mut u8 {
×
183
        self.0.as_ptr()
×
184
    }
185

186
    /// Gets the underlying raw pointer as a pointer of type T
187
    ///
188
    /// # Safety
189
    ///
190
    /// Must be called with the original type T that was used to create this pointer
191
    pub const unsafe fn as_ptr<T>(self) -> *const T {
3✔
192
        self.0.as_ptr() as *const T
3✔
193
    }
194

195
    /// Gets the underlying raw pointer as a mutable pointer of type T
196
    ///
197
    /// # Safety
198
    ///
199
    /// `T` must be the _actual_ underlying type. You're downcasting with no guardrails.
200
    pub const unsafe fn as_mut<'borrow: 'mem, T>(self) -> &'borrow mut T {
145✔
201
        unsafe { &mut *(self.0.as_ptr() as *mut T) }
145✔
202
    }
203

204
    /// Gets the underlying raw pointer as a const pointer of type T
205
    ///
206
    /// # Safety
207
    ///
208
    /// `T` must be the _actual_ underlying type. You're downcasting with no guardrails.
209
    /// You must respect AXM (aliasing xor mutability). Holding onto the borrow while
210
    /// calling as_mut is UB.
211
    ///
212
    /// Basically this is UB land. Careful.
213
    pub const unsafe fn get<'borrow: 'mem, T>(self) -> &'borrow T {
×
214
        unsafe { &*(self.0.as_ptr() as *const T) }
×
215
    }
216

217
    /// Make a const ptr out of this mut ptr
218
    pub const fn as_const<'borrow: 'mem>(self) -> PtrConst<'borrow> {
1✔
219
        PtrConst(self.0, PhantomData)
1✔
220
    }
221

222
    /// Exposes [`core::ptr::read`]
223
    ///
224
    /// # Safety
225
    ///
226
    /// `T` must be the actual underlying type of the pointed-to memory.
227
    /// The memory must be properly initialized and aligned for type `T`.
228
    pub const unsafe fn read<T>(self) -> T {
31✔
229
        unsafe { core::ptr::read(self.as_mut()) }
31✔
230
    }
231

232
    /// Exposes [`core::ptr::drop_in_place`]
233
    ///
234
    /// # Safety
235
    ///
236
    /// `T` must be the actual underlying type of the pointed-to memory.
237
    /// The memory must be properly initialized and aligned for type `T`.
238
    /// After calling this function, the memory should not be accessed again
239
    /// until it is properly reinitialized.
240
    pub unsafe fn drop_in_place<T>(self) -> PtrUninit<'mem> {
78✔
241
        unsafe { core::ptr::drop_in_place(self.as_mut::<T>()) }
78✔
242
        PtrUninit(self.0.as_ptr(), PhantomData)
78✔
243
    }
244

245
    /// Write a value to this location after dropping the existing value
246
    ///
247
    /// # Safety
248
    ///
249
    /// - The pointer must be properly aligned for T and point to allocated memory
250
    ///   that can be safely written to.
251
    /// - T must be the actual type of the object being pointed to
252
    /// - The memory must already be initialized to a valid T value
253
    pub unsafe fn replace<T>(self, value: T) -> Self {
×
254
        unsafe { self.drop_in_place::<T>().put(value) }
×
255
    }
256

257
    /// Copies data from the source pointer to this location
258
    ///
259
    /// # Safety
260
    ///
261
    /// - The destination pointer must be properly aligned and point to allocated memory
262
    ///   that can be safely written to.
263
    /// - The source pointer must point to properly initialized data.
264
    /// - Both pointers must refer to objects of the same type and size.
NEW
265
    pub unsafe fn write(self, source: PtrConst<'_>) -> Self {
×
266
        unsafe {
267
            let size = core::mem::size_of_val(&*source.as_byte_ptr());
×
268
            core::ptr::copy_nonoverlapping(source.as_byte_ptr(), self.0.as_ptr(), size);
×
269
            self
×
270
        }
271
    }
272
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc