Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ptr/src/lib.rs
6604 views
1
#![doc = include_str!("../README.md")]
2
#![no_std]
3
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4
#![expect(unsafe_code, reason = "Raw pointers are inherently unsafe.")]
5
#![doc(
6
html_logo_url = "https://bevy.org/assets/icon.png",
7
html_favicon_url = "https://bevy.org/assets/icon.png"
8
)]
9
10
use core::{
11
cell::UnsafeCell,
12
fmt::{self, Debug, Formatter, Pointer},
13
marker::PhantomData,
14
mem::{self, ManuallyDrop, MaybeUninit},
15
num::NonZeroUsize,
16
ptr::{self, NonNull},
17
};
18
19
/// Used as a type argument to [`Ptr`], [`PtrMut`], [`OwningPtr`], and [`MovingPtr`] to specify that the pointer is guaranteed
20
/// to be [aligned].
21
///
22
/// [aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
23
#[derive(Debug, Copy, Clone)]
24
pub struct Aligned;
25
26
/// Used as a type argument to [`Ptr`], [`PtrMut`], [`OwningPtr`], and [`MovingPtr`] to specify that the pointer may not [aligned].
27
///
28
/// [aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
29
#[derive(Debug, Copy, Clone)]
30
pub struct Unaligned;
31
32
/// Trait that is only implemented for [`Aligned`] and [`Unaligned`] to work around the lack of ability
33
/// to have const generics of an enum.
34
pub trait IsAligned: sealed::Sealed {
35
/// Reads the value pointed to by `ptr`.
36
///
37
/// # Safety
38
/// - `ptr` must be valid for reads.
39
/// - `ptr` must point to a valid instance of type `T`
40
/// - If this type is [`Aligned`], then `ptr` must be [properly aligned] for type `T`.
41
///
42
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
43
#[doc(hidden)]
44
unsafe fn read_ptr<T>(ptr: *const T) -> T;
45
46
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
47
/// and destination must *not* overlap.
48
///
49
/// # Safety
50
/// - `src` must be valid for reads of `count * size_of::<T>()` bytes.
51
/// - `dst` must be valid for writes of `count * size_of::<T>()` bytes.
52
/// - The region of memory beginning at `src` with a size of `count *
53
/// size_of::<T>()` bytes must *not* overlap with the region of memory
54
/// beginning at `dst` with the same size.
55
/// - If this type is [`Aligned`], then both `src` and `dst` must properly
56
/// be aligned for values of type `T`.
57
#[doc(hidden)]
58
unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
59
60
/// Reads the value pointed to by `ptr`.
61
///
62
/// # Safety
63
/// - `ptr` must be valid for reads and writes.
64
/// - `ptr` must point to a valid instance of type `T`
65
/// - If this type is [`Aligned`], then `ptr` must be [properly aligned] for type `T`.
66
/// - The value pointed to by `ptr` must be valid for dropping.
67
/// - While `drop_in_place` is executing, the only way to access parts of `ptr` is through
68
/// the `&mut Self` supplied to it's `Drop::drop` impl.
69
///
70
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
71
#[doc(hidden)]
72
unsafe fn drop_in_place<T>(ptr: *mut T);
73
}
74
75
impl IsAligned for Aligned {
76
#[inline]
77
unsafe fn read_ptr<T>(ptr: *const T) -> T {
78
// SAFETY:
79
// - The caller is required to ensure that `src` must be valid for reads.
80
// - The caller is required to ensure that `src` points to a valid instance of type `T`.
81
// - This type is `Aligned` so the caller must ensure that `src` is properly aligned for type `T`.
82
unsafe { ptr.read() }
83
}
84
85
#[inline]
86
unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
87
// SAFETY:
88
// - The caller is required to ensure that `src` must be valid for reads.
89
// - The caller is required to ensure that `dst` must be valid for writes.
90
// - The caller is required to ensure that `src` and `dst` are aligned.
91
// - The caller is required to ensure that the memory region covered by `src`
92
// and `dst`, fitting up to `count` elements do not overlap.
93
unsafe {
94
ptr::copy_nonoverlapping(src, dst, count);
95
}
96
}
97
98
#[inline]
99
unsafe fn drop_in_place<T>(ptr: *mut T) {
100
// SAFETY:
101
// - The caller is required to ensure that `ptr` must be valid for reads and writes.
102
// - The caller is required to ensure that `ptr` points to a valid instance of type `T`.
103
// - This type is `Aligned` so the caller must ensure that `ptr` is properly aligned for type `T`.
104
// - The caller is required to ensure that `ptr` points must be valid for dropping.
105
// - The caller is required to ensure that the value `ptr` points must not be used after this function
106
// call.
107
unsafe { ptr::drop_in_place(ptr) };
108
}
109
}
110
111
impl IsAligned for Unaligned {
112
#[inline]
113
unsafe fn read_ptr<T>(ptr: *const T) -> T {
114
// SAFETY:
115
// - The caller is required to ensure that `src` must be valid for reads.
116
// - The caller is required to ensure that `src` points to a valid instance of type `T`.
117
unsafe { ptr.read_unaligned() }
118
}
119
120
#[inline]
121
unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
122
// SAFETY:
123
// - The caller is required to ensure that `src` must be valid for reads.
124
// - The caller is required to ensure that `dst` must be valid for writes.
125
// - This is doing a byte-wise copy. `src` and `dst` are always guaranteed to be
126
// aligned.
127
// - The caller is required to ensure that the memory region covered by `src`
128
// and `dst`, fitting up to `count` elements do not overlap.
129
unsafe {
130
ptr::copy_nonoverlapping::<u8>(
131
src.cast::<u8>(),
132
dst.cast::<u8>(),
133
count * size_of::<T>(),
134
);
135
}
136
}
137
138
#[inline]
139
unsafe fn drop_in_place<T>(ptr: *mut T) {
140
// SAFETY:
141
// - The caller is required to ensure that `ptr` must be valid for reads and writes.
142
// - The caller is required to ensure that `ptr` points to a valid instance of type `T`.
143
// - This type is not `Aligned` so the caller does not need to ensure that `ptr` is properly aligned for type `T`.
144
// - The caller is required to ensure that `ptr` points must be valid for dropping.
145
// - The caller is required to ensure that the value `ptr` points must not be used after this function
146
// call.
147
unsafe { drop(ptr.read_unaligned()) }
148
}
149
}
150
151
mod sealed {
152
pub trait Sealed {}
153
impl Sealed for super::Aligned {}
154
impl Sealed for super::Unaligned {}
155
}
156
157
/// A newtype around [`NonNull`] that only allows conversion to read-only borrows or pointers.
158
///
159
/// This type can be thought of as the `*const T` to [`NonNull<T>`]'s `*mut T`.
160
#[repr(transparent)]
161
pub struct ConstNonNull<T: ?Sized>(NonNull<T>);
162
163
impl<T: ?Sized> ConstNonNull<T> {
164
/// Creates a new `ConstNonNull` if `ptr` is non-null.
165
///
166
/// # Examples
167
///
168
/// ```
169
/// use bevy_ptr::ConstNonNull;
170
///
171
/// let x = 0u32;
172
/// let ptr = ConstNonNull::<u32>::new(&x as *const _).expect("ptr is null!");
173
///
174
/// if let Some(ptr) = ConstNonNull::<u32>::new(core::ptr::null()) {
175
/// unreachable!();
176
/// }
177
/// ```
178
pub fn new(ptr: *const T) -> Option<Self> {
179
NonNull::new(ptr.cast_mut()).map(Self)
180
}
181
182
/// Creates a new `ConstNonNull`.
183
///
184
/// # Safety
185
///
186
/// `ptr` must be non-null.
187
///
188
/// # Examples
189
///
190
/// ```
191
/// use bevy_ptr::ConstNonNull;
192
///
193
/// let x = 0u32;
194
/// let ptr = unsafe { ConstNonNull::new_unchecked(&x as *const _) };
195
/// ```
196
///
197
/// *Incorrect* usage of this function:
198
///
199
/// ```rust,no_run
200
/// use bevy_ptr::ConstNonNull;
201
///
202
/// // NEVER DO THAT!!! This is undefined behavior. ⚠️
203
/// let ptr = unsafe { ConstNonNull::<u32>::new_unchecked(core::ptr::null()) };
204
/// ```
205
pub const unsafe fn new_unchecked(ptr: *const T) -> Self {
206
// SAFETY: This function's safety invariants are identical to `NonNull::new_unchecked`
207
// The caller must satisfy all of them.
208
unsafe { Self(NonNull::new_unchecked(ptr.cast_mut())) }
209
}
210
211
/// Returns a shared reference to the value.
212
///
213
/// # Safety
214
///
215
/// When calling this method, you have to ensure that all of the following is true:
216
///
217
/// * The pointer must be [properly aligned].
218
///
219
/// * It must be "dereferenceable" in the sense defined in [the module documentation].
220
///
221
/// * The pointer must point to an initialized instance of `T`.
222
///
223
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
224
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
225
/// In particular, while this reference exists, the memory the pointer points to must
226
/// not get mutated (except inside `UnsafeCell`).
227
///
228
/// This applies even if the result of this method is unused!
229
/// (The part about being initialized is not yet fully decided, but until
230
/// it is, the only safe approach is to ensure that they are indeed initialized.)
231
///
232
/// # Examples
233
///
234
/// ```
235
/// use bevy_ptr::ConstNonNull;
236
///
237
/// let mut x = 0u32;
238
/// let ptr = ConstNonNull::new(&mut x as *mut _).expect("ptr is null!");
239
///
240
/// let ref_x = unsafe { ptr.as_ref() };
241
/// println!("{ref_x}");
242
/// ```
243
///
244
/// [the module documentation]: core::ptr#safety
245
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
246
#[inline]
247
pub unsafe fn as_ref<'a>(&self) -> &'a T {
248
// SAFETY: This function's safety invariants are identical to `NonNull::as_ref`
249
// The caller must satisfy all of them.
250
unsafe { self.0.as_ref() }
251
}
252
}
253
254
impl<T: ?Sized> From<NonNull<T>> for ConstNonNull<T> {
255
fn from(value: NonNull<T>) -> ConstNonNull<T> {
256
ConstNonNull(value)
257
}
258
}
259
260
impl<'a, T: ?Sized> From<&'a T> for ConstNonNull<T> {
261
fn from(value: &'a T) -> ConstNonNull<T> {
262
ConstNonNull(NonNull::from(value))
263
}
264
}
265
266
impl<'a, T: ?Sized> From<&'a mut T> for ConstNonNull<T> {
267
fn from(value: &'a mut T) -> ConstNonNull<T> {
268
ConstNonNull(NonNull::from(value))
269
}
270
}
271
272
/// Type-erased borrow of some unknown type chosen when constructing this type.
273
///
274
/// This type tries to act "borrow-like" which means that:
275
/// - It should be considered immutable: its target must not be changed while this pointer is alive.
276
/// - It must always point to a valid value of whatever the pointee type is.
277
/// - The lifetime `'a` accurately represents how long the pointer is valid for.
278
/// - If `A` is [`Aligned`], the pointer must always be [properly aligned] for the unknown pointee type.
279
///
280
/// It may be helpful to think of this type as similar to `&'a dyn Any` but without
281
/// the metadata and able to point to data that does not correspond to a Rust type.
282
///
283
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
284
#[derive(Copy, Clone)]
285
#[repr(transparent)]
286
pub struct Ptr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a u8, A)>);
287
288
/// Type-erased mutable borrow of some unknown type chosen when constructing this type.
289
///
290
/// This type tries to act "borrow-like" which means that:
291
/// - Pointer is considered exclusive and mutable. It cannot be cloned as this would lead to
292
/// aliased mutability.
293
/// - It must always point to a valid value of whatever the pointee type is.
294
/// - The lifetime `'a` accurately represents how long the pointer is valid for.
295
/// - If `A` is [`Aligned`], the pointer must always be [properly aligned] for the unknown pointee type.
296
///
297
/// It may be helpful to think of this type as similar to `&'a mut dyn Any` but without
298
/// the metadata and able to point to data that does not correspond to a Rust type.
299
///
300
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
301
#[repr(transparent)]
302
pub struct PtrMut<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
303
304
/// Type-erased [`Box`]-like pointer to some unknown type chosen when constructing this type.
305
///
306
/// Conceptually represents ownership of whatever data is being pointed to and so is
307
/// responsible for calling its `Drop` impl. This pointer is _not_ responsible for freeing
308
/// the memory pointed to by this pointer as it may be pointing to an element in a `Vec` or
309
/// to a local in a function etc.
310
///
311
/// This type tries to act "borrow-like" which means that:
312
/// - Pointer should be considered exclusive and mutable. It cannot be cloned as this would lead
313
/// to aliased mutability and potentially use after free bugs.
314
/// - It must always point to a valid value of whatever the pointee type is.
315
/// - The lifetime `'a` accurately represents how long the pointer is valid for.
316
/// - If `A` is [`Aligned`], the pointer must always be [properly aligned] for the unknown pointee type.
317
///
318
/// It may be helpful to think of this type as similar to `&'a mut ManuallyDrop<dyn Any>` but
319
/// without the metadata and able to point to data that does not correspond to a Rust type.
320
///
321
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
322
/// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
323
#[repr(transparent)]
324
pub struct OwningPtr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
325
326
/// A [`Box`]-like pointer for moving a value to a new memory location without needing to pass by
327
/// value.
328
///
329
/// Conceptually represents ownership of whatever data is being pointed to and will call its
330
/// [`Drop`] impl upon being dropped. This pointer is _not_ responsible for freeing
331
/// the memory pointed to by this pointer as it may be pointing to an element in a `Vec` or
332
/// to a local in a function etc.
333
///
334
/// This type tries to act "borrow-like" which means that:
335
/// - Pointer should be considered exclusive and mutable. It cannot be cloned as this would lead
336
/// to aliased mutability and potentially use after free bugs.
337
/// - It must always point to a valid value of whatever the pointee type is.
338
/// - The lifetime `'a` accurately represents how long the pointer is valid for.
339
/// - It does not support pointer arithmetic in any way.
340
/// - If `A` is [`Aligned`], the pointer must always be [properly aligned] for the type `T`.
341
///
342
/// A value can be deconstructed into its fields via [`deconstruct_moving_ptr`], see it's documentation
343
/// for an example on how to use it.
344
///
345
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
346
/// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
347
#[repr(transparent)]
348
pub struct MovingPtr<'a, T, A: IsAligned = Aligned>(NonNull<T>, PhantomData<(&'a mut T, A)>);
349
350
macro_rules! impl_ptr {
351
($ptr:ident) => {
352
impl<'a> $ptr<'a, Aligned> {
353
/// Removes the alignment requirement of this pointer
354
pub fn to_unaligned(self) -> $ptr<'a, Unaligned> {
355
$ptr(self.0, PhantomData)
356
}
357
}
358
359
impl<'a, A: IsAligned> From<$ptr<'a, A>> for NonNull<u8> {
360
fn from(ptr: $ptr<'a, A>) -> Self {
361
ptr.0
362
}
363
}
364
365
impl<A: IsAligned> $ptr<'_, A> {
366
/// Calculates the offset from a pointer.
367
/// As the pointer is type-erased, there is no size information available. The provided
368
/// `count` parameter is in raw bytes.
369
///
370
/// *See also: [`ptr::offset`][ptr_offset]*
371
///
372
/// # Safety
373
/// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
374
/// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
375
/// be unaligned for the pointee type.
376
/// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
377
///
378
/// [ptr_offset]: https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
379
#[inline]
380
pub unsafe fn byte_offset(self, count: isize) -> Self {
381
Self(
382
// SAFETY: The caller upholds safety for `offset` and ensures the result is not null.
383
unsafe { NonNull::new_unchecked(self.as_ptr().offset(count)) },
384
PhantomData,
385
)
386
}
387
388
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
389
/// As the pointer is type-erased, there is no size information available. The provided
390
/// `count` parameter is in raw bytes.
391
///
392
/// *See also: [`ptr::add`][ptr_add]*
393
///
394
/// # Safety
395
/// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
396
/// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
397
/// be unaligned for the pointee type.
398
/// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
399
///
400
/// [ptr_add]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add
401
#[inline]
402
pub unsafe fn byte_add(self, count: usize) -> Self {
403
Self(
404
// SAFETY: The caller upholds safety for `add` and ensures the result is not null.
405
unsafe { NonNull::new_unchecked(self.as_ptr().add(count)) },
406
PhantomData,
407
)
408
}
409
}
410
411
impl<A: IsAligned> Pointer for $ptr<'_, A> {
412
#[inline]
413
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
414
Pointer::fmt(&self.0, f)
415
}
416
}
417
418
impl Debug for $ptr<'_, Aligned> {
419
#[inline]
420
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
421
write!(f, "{}<Aligned>({:?})", stringify!($ptr), self.0)
422
}
423
}
424
425
impl Debug for $ptr<'_, Unaligned> {
426
#[inline]
427
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
428
write!(f, "{}<Unaligned>({:?})", stringify!($ptr), self.0)
429
}
430
}
431
};
432
}
433
434
impl_ptr!(Ptr);
435
impl_ptr!(PtrMut);
436
impl_ptr!(OwningPtr);
437
438
impl<'a, T> MovingPtr<'a, T, Aligned> {
439
/// Removes the alignment requirement of this pointer
440
#[inline]
441
pub fn to_unaligned(self) -> MovingPtr<'a, T, Unaligned> {
442
let value = MovingPtr(self.0, PhantomData);
443
mem::forget(self);
444
value
445
}
446
447
/// Consumes a value and creates an [`MovingPtr`] to it while ensuring a double drop does not happen.
448
#[inline]
449
pub fn make<F: FnOnce(MovingPtr<'_, T>) -> R, R>(val: T, f: F) -> R {
450
let mut val = MaybeUninit::new(val);
451
// SAFETY: The value behind the pointer will not get dropped or observed later.
452
f(unsafe { MovingPtr::from_value(&mut val) })
453
}
454
455
/// Creates a [`MovingPtr`] from a provided value of type `T`.
456
///
457
/// # Safety
458
/// - `value` must store a properly initialized value of type `T`.
459
/// - Once the returned [`MovingPtr`] has been used, `value` must be treated as
460
/// it were uninitialized unless it was explicitly leaked via [`core::mem::forget`].
461
#[inline]
462
pub unsafe fn from_value(value: &'a mut MaybeUninit<T>) -> Self {
463
// SAFETY:
464
// - MaybeUninit<T> has the same memory layout as T
465
// - The caller guarantees that `value` must point to a valid instance of type `T`.
466
MovingPtr(NonNull::from(value).cast::<T>(), PhantomData)
467
}
468
}
469
470
impl<'a, T, A: IsAligned> MovingPtr<'_, T, A> {
471
/// Creates a new instance from a raw pointer.
472
///
473
/// # Safety
474
/// - `inner` must point to valid value of `T`.
475
/// - If the `A` type parameter is [`Aligned`] then `inner` must be be [properly aligned] for `T`.
476
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
477
/// - The lifetime `'a` must be constrained such that this [`MovingPtr`] will stay valid and nothing
478
/// else can read or mutate the pointee while this [`MovingPtr`] is live.
479
///
480
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
481
#[inline]
482
pub unsafe fn new(inner: NonNull<T>) -> Self {
483
Self(inner, PhantomData)
484
}
485
486
/// Partially moves out some fields inside of `self`.
487
///
488
/// The partially returned value is returned back pointing to `MaybeUninit<T>`.
489
///
490
/// # Safety
491
/// - The call into `f` must not complete having dropped the provided pointer.
492
/// - The fields moved out of in `f` must not be accessed or dropped after this function returns.
493
///
494
/// As a result, it is strongly recommended to call [`forget`] on the provided pointer once the
495
/// partial deconstruction has completed.
496
///
497
/// # Example
498
///
499
/// ```
500
/// use core::mem::{offset_of, MaybeUninit};
501
/// use bevy_ptr::MovingPtr;
502
/// # use bevy_ptr::Unaligned;
503
/// # struct FieldAType(usize);
504
/// # struct FieldBType(usize);
505
/// # struct FieldCType(usize);
506
/// # fn insert<T>(_ptr: MovingPtr<'_, T, Unaligned>) {}
507
///
508
/// struct Parent {
509
/// field_a: FieldAType,
510
/// field_b: FieldBType,
511
/// field_c: FieldCType,
512
/// }
513
///
514
/// # let parent = Parent {
515
/// # field_a: FieldAType(0),
516
/// # field_b: FieldBType(0),
517
/// # field_c: FieldCType(0),
518
/// # };
519
///
520
/// MovingPtr::make(parent, |parent_ptr| unsafe {
521
/// // SAFETY:
522
/// // - It is impossible for the provided closure to drop the provided pointer as `move_field` cannot panic.
523
/// // - `field_a` and `field_b` are moved out of but never accessed after this.
524
/// let partial_parent = MovingPtr::partial_move(parent_ptr, |parent_ptr| {
525
/// bevy_ptr::deconstruct_moving_ptr!(parent_ptr, Parent {
526
/// field_a: FieldAType => { insert(field_a) },
527
/// field_b: FieldBType => { insert(field_b) },
528
/// });
529
/// });
530
///
531
/// // Move the rest of fields out of the parent.
532
/// bevy_ptr::deconstruct_moving_ptr!(partial_parent, Parent {
533
/// field_c: FieldBType => { insert(field_c) },
534
/// });
535
/// });
536
/// ```
537
///
538
/// [`forget`]: core::mem::forget
539
#[inline]
540
pub unsafe fn partial_move(
541
ptr: MovingPtr<'a, T, A>,
542
f: impl FnOnce(MovingPtr<'a, T, A>),
543
) -> MovingPtr<'a, MaybeUninit<T>, A> {
544
let partial_ptr = ptr.0;
545
f(ptr);
546
MovingPtr(partial_ptr.cast::<MaybeUninit<T>>(), PhantomData)
547
}
548
549
/// Reads the value pointed to by this pointer.
550
#[inline]
551
pub fn read(self) -> T {
552
// SAFETY:
553
// - `self.0` must be valid for reads as this type owns the value it points to.
554
// - `self.0` must always point to a valid instance of type `T`
555
// - If `A` is [`Aligned`], then `ptr` must be properly aligned for type `T`.
556
let value = unsafe { A::read_ptr(self.0.as_ptr()) };
557
mem::forget(self);
558
value
559
}
560
561
/// Writes the value pointed to by this pointer to a provided location.
562
///
563
/// This does *not* drop the value stored at `dst` and it's the caller's responsibility
564
/// to ensure that it's properly dropped.
565
///
566
/// # Safety
567
/// - `dst` must be valid for writes.
568
/// - If the `A` type parameter is [`Aligned`] then `dst` must be [properly aligned] for `T`.
569
///
570
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
571
#[inline]
572
pub unsafe fn write_to(self, dst: *mut T) {
573
let src = self.0.as_ptr();
574
mem::forget(self);
575
// SAFETY:
576
// - `src` must be valid for reads as this pointer is considered to own the value it points to.
577
// - The caller is required to ensure that `dst` must be valid for writes.
578
// - As `A` is `Aligned`, the caller is required to ensure that `dst` is aligned and `src` must
579
// be aligned by the type's invariants.
580
unsafe { A::copy_nonoverlapping(src, dst, 1) };
581
}
582
583
/// Writes the value pointed to by this pointer into `dst`.
584
///
585
/// The value previously stored at `dst` will be dropped.
586
#[inline]
587
pub fn assign_to(self, dst: &mut T) {
588
// SAFETY:
589
// - `dst` is a mutable borrow, it must point to a valid instance of `T`.
590
// - `dst` is a mutable borrow, it must point to value that is valid for dropping.
591
// - `dst` is a mutable borrow, it must not alias any other access.
592
unsafe {
593
ptr::drop_in_place(dst);
594
}
595
// SAFETY:
596
// - `dst` is a mutable borrow, it must be valid for writes.
597
// - `dst` is a mutable borrow, it must always be aligned.
598
unsafe {
599
self.write_to(dst);
600
}
601
}
602
603
/// Creates a [`MovingPtr`] for a specific field within `self`. This is a building block for
604
/// [`deconstruct_moving_ptr`] and should generally not be accessed directly.
605
///
606
/// This function is explicitly made for deconstructive moves.
607
///
608
/// The correct `byte_offset` for a field can be obtained via [`core::mem::offset_of`].
609
///
610
/// The returned value will always be considered unaligned as `repr(packed)` types may result in
611
/// unaligned fields. The pointer is convertible back into an aligned one using the [`TryFrom`] impl.
612
///
613
/// # Safety
614
/// - `U` must be the correct type for the field at `byte_offset` within `self`.
615
/// - `self` should not be accessed or dropped as if it were a complete value.
616
/// Other fields that have not been moved out of may still be accessed or dropped separately.
617
/// - This function cannot alias the field with any other access, including other calls to [`move_field`]
618
/// for the same field, without first calling [`forget`] on it first.
619
///
620
/// A result of the above invariants means that any operation that could cause `self` to be dropped while
621
/// the pointers to the fields are held will result in undefined behavior. This requires exctra caution
622
/// around code that may panic. See the example below for an example of how to safely use this function.
623
///
624
/// # Example
625
///
626
/// ```
627
/// use core::mem::offset_of;
628
/// use bevy_ptr::MovingPtr;
629
/// # use bevy_ptr::Unaligned;
630
/// # struct FieldAType(usize);
631
/// # struct FieldBType(usize);
632
/// # struct FieldCType(usize);
633
/// # fn insert<T>(_ptr: MovingPtr<'_, T, Unaligned>) {}
634
///
635
/// struct Parent {
636
/// field_a: FieldAType,
637
/// field_b: FieldBType,
638
/// field_c: FieldCType,
639
/// }
640
///
641
/// # let parent = Parent {
642
/// # field_a: FieldAType(0),
643
/// # field_b: FieldBType(0),
644
/// # field_c: FieldCType(0),
645
/// # };
646
///
647
/// MovingPtr::make(parent, |parent_ptr| unsafe {
648
/// let field_a = parent_ptr.move_field::<FieldAType>(offset_of!(Parent, field_a));
649
/// let field_b = parent_ptr.move_field::<FieldBType>(offset_of!(Parent, field_b));
650
/// let field_c = parent_ptr.move_field::<FieldCType>(offset_of!(Parent, field_c));
651
/// // Each call to insert may panic! Ensure that `parent_ptr` cannot be dropped before
652
/// // calling them!
653
/// core::mem::forget(parent_ptr);
654
/// insert(field_a);
655
/// insert(field_b);
656
/// insert(field_c);
657
/// });
658
/// ```
659
///
660
/// [`forget`]: core::mem::forget
661
/// [`move_field`]: Self::move_field
662
#[inline]
663
#[doc(hidden)]
664
pub unsafe fn move_field<U>(&self, byte_offset: usize) -> MovingPtr<'a, U, Unaligned> {
665
MovingPtr(
666
// SAFETY: The caller must ensure that `U` is the correct type for the field at `byte_offset`.
667
unsafe { self.0.byte_add(byte_offset) }.cast::<U>(),
668
PhantomData,
669
)
670
}
671
}
672
673
impl<'a, T, A: IsAligned> MovingPtr<'a, MaybeUninit<T>, A> {
674
/// Creates a [`MovingPtr`] pointing to a valid instance of `T`.
675
///
676
/// See also: [`MaybeUninit::assume_init`].
677
///
678
/// # Safety
679
/// It's up to the caller to ensure that the value pointed to by `self`
680
/// is really in an initialized state. Calling this when the content is not yet
681
/// fully initialized causes immediate undefined behavior.
682
#[inline]
683
pub unsafe fn assume_init(self) -> MovingPtr<'a, T, A> {
684
let value = MovingPtr(self.0.cast::<T>(), PhantomData);
685
mem::forget(self);
686
value
687
}
688
}
689
690
impl<T, A: IsAligned> Pointer for MovingPtr<'_, T, A> {
691
#[inline]
692
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
693
Pointer::fmt(&self.0, f)
694
}
695
}
696
697
impl<T> Debug for MovingPtr<'_, T, Aligned> {
698
#[inline]
699
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
700
write!(f, "{}<Aligned>({:?})", stringify!($ptr), self.0)
701
}
702
}
703
704
impl<T> Debug for MovingPtr<'_, T, Unaligned> {
705
#[inline]
706
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
707
write!(f, "{}<Unaligned>({:?})", stringify!($ptr), self.0)
708
}
709
}
710
711
impl<'a, T, A: IsAligned> From<MovingPtr<'a, T, A>> for OwningPtr<'a, A> {
712
#[inline]
713
fn from(value: MovingPtr<'a, T, A>) -> Self {
714
// SAFETY:
715
// - `value.0` must always point to valid value of type `T`.
716
// - The type parameter `A` is mirrored from input to output, keeping the same alignment guarantees.
717
// - `value.0` by construction must have correct provenance to allow read and writes of type `T`.
718
// - The lifetime `'a` is mirrored from input to output, keeping the same lifetime guarantees.
719
// - `OwningPtr` maintains the same aliasing invariants as `MovingPtr`.
720
let ptr = unsafe { OwningPtr::new(value.0.cast::<u8>()) };
721
mem::forget(value);
722
ptr
723
}
724
}
725
726
impl<'a, T> TryFrom<MovingPtr<'a, T, Unaligned>> for MovingPtr<'a, T, Aligned> {
727
type Error = MovingPtr<'a, T, Unaligned>;
728
#[inline]
729
fn try_from(value: MovingPtr<'a, T, Unaligned>) -> Result<Self, Self::Error> {
730
let ptr = value.0;
731
if ptr.as_ptr().is_aligned() {
732
Ok(MovingPtr(ptr, PhantomData))
733
} else {
734
Err(value)
735
}
736
}
737
}
738
739
impl<T, A: IsAligned> Drop for MovingPtr<'_, T, A> {
740
fn drop(&mut self) {
741
// SAFETY:
742
// - `self.0` must be valid for reads and writes as this pointer type owns the value it points to.
743
// - `self.0` must always point to a valid instance of type `T`
744
// - If `A` is `Aligned`, then `ptr` must be properly aligned for type `T` by construction.
745
// - `self.0` owns the value it points to so it must always be valid for dropping until this pointer is dropped.
746
// - This type owns the value it points to, so it's required to not mutably alias value that it points to.
747
unsafe { A::drop_in_place(self.0.as_ptr()) };
748
}
749
}
750
751
impl<'a, A: IsAligned> Ptr<'a, A> {
752
/// Creates a new instance from a raw pointer.
753
///
754
/// # Safety
755
/// - `inner` must point to valid value of whatever the pointee type is.
756
/// - If the `A` type parameter is [`Aligned`] then `inner` must be be [properly aligned]for the pointee type.
757
/// - `inner` must have correct provenance to allow reads of the pointee type.
758
/// - The lifetime `'a` must be constrained such that this [`Ptr`] will stay valid and nothing
759
/// can mutate the pointee while this [`Ptr`] is live except through an [`UnsafeCell`].
760
///
761
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
762
#[inline]
763
pub unsafe fn new(inner: NonNull<u8>) -> Self {
764
Self(inner, PhantomData)
765
}
766
767
/// Transforms this [`Ptr`] into an [`PtrMut`]
768
///
769
/// # Safety
770
/// * The data pointed to by this `Ptr` must be valid for writes.
771
/// * There must be no active references (mutable or otherwise) to the data underlying this `Ptr`.
772
/// * Another [`PtrMut`] for the same [`Ptr`] must not be created until the first is dropped.
773
#[inline]
774
pub unsafe fn assert_unique(self) -> PtrMut<'a, A> {
775
PtrMut(self.0, PhantomData)
776
}
777
778
/// Transforms this [`Ptr<T>`] into a `&T` with the same lifetime
779
///
780
/// # Safety
781
/// - `T` must be the erased pointee type for this [`Ptr`].
782
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be be [properly aligned]
783
/// for the pointee type `T`.
784
///
785
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
786
#[inline]
787
pub unsafe fn deref<T>(self) -> &'a T {
788
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
789
// SAFETY: The caller ensures the pointee is of type `T` and the pointer can be dereferenced.
790
unsafe { &*ptr }
791
}
792
793
/// Gets the underlying pointer, erasing the associated lifetime.
794
///
795
/// If possible, it is strongly encouraged to use [`deref`](Self::deref) over this function,
796
/// as it retains the lifetime.
797
#[inline]
798
pub fn as_ptr(self) -> *mut u8 {
799
self.0.as_ptr()
800
}
801
}
802
803
impl<'a, T: ?Sized> From<&'a T> for Ptr<'a> {
804
#[inline]
805
fn from(val: &'a T) -> Self {
806
// SAFETY: The returned pointer has the same lifetime as the passed reference.
807
// Access is immutable.
808
unsafe { Self::new(NonNull::from(val).cast()) }
809
}
810
}
811
812
impl<'a, A: IsAligned> PtrMut<'a, A> {
813
/// Creates a new instance from a raw pointer.
814
///
815
/// # Safety
816
/// - `inner` must point to valid value of whatever the pointee type is.
817
/// - If the `A` type parameter is [`Aligned`] then `inner` must be be [properly aligned] for the pointee type.
818
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
819
/// - The lifetime `'a` must be constrained such that this [`PtrMut`] will stay valid and nothing
820
/// else can read or mutate the pointee while this [`PtrMut`] is live.
821
///
822
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
823
#[inline]
824
pub unsafe fn new(inner: NonNull<u8>) -> Self {
825
Self(inner, PhantomData)
826
}
827
828
/// Transforms this [`PtrMut`] into an [`OwningPtr`]
829
///
830
/// # Safety
831
/// Must have right to drop or move out of [`PtrMut`].
832
#[inline]
833
pub unsafe fn promote(self) -> OwningPtr<'a, A> {
834
OwningPtr(self.0, PhantomData)
835
}
836
837
/// Transforms this [`PtrMut<T>`] into a `&mut T` with the same lifetime
838
///
839
/// # Safety
840
/// - `T` must be the erased pointee type for this [`PtrMut`].
841
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be be [properly aligned]
842
/// for the pointee type `T`.
843
///
844
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
845
#[inline]
846
pub unsafe fn deref_mut<T>(self) -> &'a mut T {
847
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
848
// SAFETY: The caller ensures the pointee is of type `T` and the pointer can be dereferenced.
849
unsafe { &mut *ptr }
850
}
851
852
/// Gets the underlying pointer, erasing the associated lifetime.
853
///
854
/// If possible, it is strongly encouraged to use [`deref_mut`](Self::deref_mut) over
855
/// this function, as it retains the lifetime.
856
#[inline]
857
pub fn as_ptr(&self) -> *mut u8 {
858
self.0.as_ptr()
859
}
860
861
/// Gets a [`PtrMut`] from this with a smaller lifetime.
862
#[inline]
863
pub fn reborrow(&mut self) -> PtrMut<'_, A> {
864
// SAFETY: the ptrmut we're borrowing from is assumed to be valid
865
unsafe { PtrMut::new(self.0) }
866
}
867
868
/// Gets an immutable reference from this mutable reference
869
#[inline]
870
pub fn as_ref(&self) -> Ptr<'_, A> {
871
// SAFETY: The `PtrMut` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
872
unsafe { Ptr::new(self.0) }
873
}
874
}
875
876
impl<'a, T: ?Sized> From<&'a mut T> for PtrMut<'a> {
877
#[inline]
878
fn from(val: &'a mut T) -> Self {
879
// SAFETY: The returned pointer has the same lifetime as the passed reference.
880
// The reference is mutable, and thus will not alias.
881
unsafe { Self::new(NonNull::from(val).cast()) }
882
}
883
}
884
885
impl<'a> OwningPtr<'a> {
886
/// This exists mostly to reduce compile times;
887
/// code is only duplicated per type, rather than per function called.
888
///
889
/// # Safety
890
///
891
/// Safety constraints of [`PtrMut::promote`] must be upheld.
892
unsafe fn make_internal<T>(temp: &mut ManuallyDrop<T>) -> OwningPtr<'_> {
893
// SAFETY: The constraints of `promote` are upheld by caller.
894
unsafe { PtrMut::from(&mut *temp).promote() }
895
}
896
897
/// Consumes a value and creates an [`OwningPtr`] to it while ensuring a double drop does not happen.
898
#[inline]
899
pub fn make<T, F: FnOnce(OwningPtr<'_>) -> R, R>(val: T, f: F) -> R {
900
let mut val = ManuallyDrop::new(val);
901
// SAFETY: The value behind the pointer will not get dropped or observed later,
902
// so it's safe to promote it to an owning pointer.
903
f(unsafe { Self::make_internal(&mut val) })
904
}
905
}
906
907
impl<'a, A: IsAligned> OwningPtr<'a, A> {
908
/// Creates a new instance from a raw pointer.
909
///
910
/// # Safety
911
/// - `inner` must point to valid value of whatever the pointee type is.
912
/// - If the `A` type parameter is [`Aligned`] then `inner` must be [properly aligned] for the pointee type.
913
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
914
/// - The lifetime `'a` must be constrained such that this [`OwningPtr`] will stay valid and nothing
915
/// else can read or mutate the pointee while this [`OwningPtr`] is live.
916
///
917
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
918
#[inline]
919
pub unsafe fn new(inner: NonNull<u8>) -> Self {
920
Self(inner, PhantomData)
921
}
922
923
/// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
924
///
925
/// # Safety
926
/// - `T` must be the erased pointee type for this [`OwningPtr`].
927
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be be [properly aligned]
928
/// for the pointee type `T`.
929
///
930
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
931
#[inline]
932
pub unsafe fn read<T>(self) -> T {
933
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
934
// SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `read`.
935
unsafe { ptr.read() }
936
}
937
938
/// Casts to a concrete type as a [`MovingPtr`].
939
///
940
/// # Safety
941
/// - `T` must be the erased pointee type for this [`OwningPtr`].
942
#[inline]
943
pub unsafe fn cast<T>(self) -> MovingPtr<'a, T, A> {
944
MovingPtr(self.0.cast::<T>(), PhantomData)
945
}
946
947
/// Consumes the [`OwningPtr`] to drop the underlying data of type `T`.
948
///
949
/// # Safety
950
/// - `T` must be the erased pointee type for this [`OwningPtr`].
951
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be be [properly aligned]
952
/// for the pointee type `T`.
953
///
954
/// [properly aligned]: https://doc.rust-lang.org/std/ptr/index.html#alignment
955
#[inline]
956
pub unsafe fn drop_as<T>(self) {
957
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
958
// SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `drop_in_place`.
959
unsafe {
960
ptr.drop_in_place();
961
}
962
}
963
964
/// Gets the underlying pointer, erasing the associated lifetime.
965
///
966
/// If possible, it is strongly encouraged to use the other more type-safe functions
967
/// over this function.
968
#[inline]
969
pub fn as_ptr(&self) -> *mut u8 {
970
self.0.as_ptr()
971
}
972
973
/// Gets an immutable pointer from this owned pointer.
974
#[inline]
975
pub fn as_ref(&self) -> Ptr<'_, A> {
976
// SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
977
unsafe { Ptr::new(self.0) }
978
}
979
980
/// Gets a mutable pointer from this owned pointer.
981
#[inline]
982
pub fn as_mut(&mut self) -> PtrMut<'_, A> {
983
// SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
984
unsafe { PtrMut::new(self.0) }
985
}
986
}
987
988
impl<'a> OwningPtr<'a, Unaligned> {
989
/// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
990
///
991
/// # Safety
992
/// - `T` must be the erased pointee type for this [`OwningPtr`].
993
pub unsafe fn read_unaligned<T>(self) -> T {
994
let ptr = self.as_ptr().cast::<T>();
995
// SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `read_unaligned`.
996
unsafe { ptr.read_unaligned() }
997
}
998
}
999
1000
/// Conceptually equivalent to `&'a [T]` but with length information cut out for performance reasons
1001
pub struct ThinSlicePtr<'a, T> {
1002
ptr: NonNull<T>,
1003
#[cfg(debug_assertions)]
1004
len: usize,
1005
_marker: PhantomData<&'a [T]>,
1006
}
1007
1008
impl<'a, T> ThinSlicePtr<'a, T> {
1009
#[inline]
1010
/// Indexes the slice without doing bounds checks
1011
///
1012
/// # Safety
1013
/// `index` must be in-bounds.
1014
pub unsafe fn get(self, index: usize) -> &'a T {
1015
#[cfg(debug_assertions)]
1016
debug_assert!(index < self.len);
1017
1018
let ptr = self.ptr.as_ptr();
1019
// SAFETY: `index` is in-bounds so the resulting pointer is valid to dereference.
1020
unsafe { &*ptr.add(index) }
1021
}
1022
}
1023
1024
impl<'a, T> Clone for ThinSlicePtr<'a, T> {
1025
fn clone(&self) -> Self {
1026
*self
1027
}
1028
}
1029
1030
impl<'a, T> Copy for ThinSlicePtr<'a, T> {}
1031
1032
impl<'a, T> From<&'a [T]> for ThinSlicePtr<'a, T> {
1033
#[inline]
1034
fn from(slice: &'a [T]) -> Self {
1035
let ptr = slice.as_ptr().cast_mut();
1036
Self {
1037
// SAFETY: a reference can never be null
1038
ptr: unsafe { NonNull::new_unchecked(ptr.debug_ensure_aligned()) },
1039
#[cfg(debug_assertions)]
1040
len: slice.len(),
1041
_marker: PhantomData,
1042
}
1043
}
1044
}
1045
1046
/// Creates a dangling pointer with specified alignment.
1047
/// See [`NonNull::dangling`].
1048
pub const fn dangling_with_align(align: NonZeroUsize) -> NonNull<u8> {
1049
debug_assert!(align.is_power_of_two(), "Alignment must be power of two.");
1050
// SAFETY: The pointer will not be null, since it was created
1051
// from the address of a `NonZero<usize>`.
1052
// TODO: use https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.with_addr once stabilized
1053
unsafe { NonNull::new_unchecked(ptr::null_mut::<u8>().wrapping_add(align.get())) }
1054
}
1055
1056
mod private {
1057
use core::cell::UnsafeCell;
1058
1059
pub trait SealedUnsafeCell {}
1060
impl<'a, T> SealedUnsafeCell for &'a UnsafeCell<T> {}
1061
}
1062
1063
/// Extension trait for helper methods on [`UnsafeCell`]
1064
pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell {
1065
/// # Safety
1066
/// - The returned value must be unique and not alias any mutable or immutable references to the contents of the [`UnsafeCell`].
1067
/// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
1068
unsafe fn deref_mut(self) -> &'a mut T;
1069
1070
/// # Safety
1071
/// - For the lifetime `'a` of the returned value you must not construct a mutable reference to the contents of the [`UnsafeCell`].
1072
/// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
1073
unsafe fn deref(self) -> &'a T;
1074
1075
/// Returns a copy of the contained value.
1076
///
1077
/// # Safety
1078
/// - The [`UnsafeCell`] must not currently have a mutable reference to its content.
1079
/// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
1080
unsafe fn read(self) -> T
1081
where
1082
T: Copy;
1083
}
1084
1085
impl<'a, T> UnsafeCellDeref<'a, T> for &'a UnsafeCell<T> {
1086
#[inline]
1087
unsafe fn deref_mut(self) -> &'a mut T {
1088
// SAFETY: The caller upholds the alias rules.
1089
unsafe { &mut *self.get() }
1090
}
1091
#[inline]
1092
unsafe fn deref(self) -> &'a T {
1093
// SAFETY: The caller upholds the alias rules.
1094
unsafe { &*self.get() }
1095
}
1096
1097
#[inline]
1098
unsafe fn read(self) -> T
1099
where
1100
T: Copy,
1101
{
1102
// SAFETY: The caller upholds the alias rules.
1103
unsafe { self.get().read() }
1104
}
1105
}
1106
1107
trait DebugEnsureAligned {
1108
fn debug_ensure_aligned(self) -> Self;
1109
}
1110
1111
// Disable this for miri runs as it already checks if pointer to reference
1112
// casts are properly aligned.
1113
#[cfg(all(debug_assertions, not(miri)))]
1114
impl<T: Sized> DebugEnsureAligned for *mut T {
1115
#[track_caller]
1116
fn debug_ensure_aligned(self) -> Self {
1117
let align = align_of::<T>();
1118
// Implementation shamelessly borrowed from the currently unstable
1119
// ptr.is_aligned_to.
1120
//
1121
// Replace once https://github.com/rust-lang/rust/issues/96284 is stable.
1122
assert_eq!(
1123
self as usize & (align - 1),
1124
0,
1125
"pointer is not aligned. Address {:p} does not have alignment {} for type {}",
1126
self,
1127
align,
1128
core::any::type_name::<T>()
1129
);
1130
self
1131
}
1132
}
1133
1134
#[cfg(any(not(debug_assertions), miri))]
1135
impl<T: Sized> DebugEnsureAligned for *mut T {
1136
#[inline(always)]
1137
fn debug_ensure_aligned(self) -> Self {
1138
self
1139
}
1140
}
1141
1142
/// Deconstructs a [`MovingPtr`] into its individual fields.
1143
///
1144
/// This consumes the [`MovingPtr`] and hands out [`MovingPtr`] wrappers around
1145
/// pointers to each of its fields. The value will *not* be dropped.
1146
///
1147
/// The field move expressions will be executed in the order they're provided to the macro.
1148
/// In the example below, the call to [`assign_to`] for `field_a` will always run before the
1149
/// calls for `field_b` and `field_c`.
1150
///
1151
/// # Safety
1152
/// This macro generates unsafe code and must be set up correctly to avoid undefined behavior.
1153
/// - The provided type must match the type of the value pointed to by the [`MovingPtr`].
1154
/// - The type and name of the fields must match the type's definition. For tuples and tuple structs,
1155
/// this would be the tuple indices.
1156
///
1157
/// # Example
1158
///
1159
/// ```
1160
/// use core::mem::{offset_of, MaybeUninit};
1161
/// use bevy_ptr::MovingPtr;
1162
/// # use bevy_ptr::Unaligned;
1163
/// # struct FieldAType(usize);
1164
/// # struct FieldBType(usize);
1165
/// # struct FieldCType(usize);
1166
///
1167
/// pub struct Parent {
1168
/// pub field_a: FieldAType,
1169
/// pub field_b: FieldBType,
1170
/// pub field_c: FieldCType,
1171
/// }
1172
///
1173
/// let parent = Parent {
1174
/// field_a: FieldAType(11),
1175
/// field_b: FieldBType(22),
1176
/// field_c: FieldCType(33),
1177
/// };
1178
///
1179
/// let mut target_a = FieldAType(101);
1180
/// let mut target_b = FieldBType(102);
1181
/// let mut target_c = FieldCType(103);
1182
///
1183
/// MovingPtr::make(parent, |parent_ptr| unsafe {
1184
/// bevy_ptr::deconstruct_moving_ptr!(parent_ptr, Parent {
1185
/// // The field name and type must match the name used in the type definition.
1186
/// // Each one will be a `MovingPtr` of the supplied type
1187
/// field_a: FieldAType => { field_a.assign_to(&mut target_a) },
1188
/// field_b: FieldBType => { field_b.assign_to(&mut target_b) },
1189
/// field_c: FieldCType => { field_c.assign_to(&mut target_c) },
1190
/// });
1191
/// });
1192
///
1193
/// assert_eq!(target_a.0, 11);
1194
/// assert_eq!(target_b.0, 22);
1195
/// assert_eq!(target_c.0, 33);
1196
/// ```
1197
///
1198
/// [`assign_to`]: MovingPtr::assign_to
1199
#[macro_export]
1200
macro_rules! deconstruct_moving_ptr {
1201
($ptr:ident, $self_type:tt {$($field_name:tt: $field_type:tt => $field_block:block,)*}) => {
1202
$(let $field_name = $ptr.move_field::<$field_type>(core::mem::offset_of!($self_type, $field_name));)*
1203
// Each field block may panic! Ensure that `parent_ptr` cannot be dropped before
1204
// calling them!
1205
core::mem::forget($ptr);
1206
$($field_block)*
1207
};
1208
}
1209
1210