movable_ref/pointer/self_ref.rs
1//! SelfRef type definition
2//!
3//! This module contains the main `SelfRef` type that represents a relative pointer.
4
5use crate::metadata::PointerRecomposition;
6use crate::offset::{Nullable, Offset, Ptr};
7use crate::pointer::unreachable::UncheckedOptionExt as _;
8use core::marker::PhantomData;
9use core::mem::MaybeUninit;
10use std::ptr::NonNull;
11
12type GuardPayload<T> = Option<NonNull<T>>;
13
14#[inline]
15fn guard_payload_from<T: ?Sized>(target: Option<NonNull<T>>) -> GuardPayload<T> {
16 #[cfg(feature = "debug-guards")]
17 {
18 target
19 }
20 #[cfg(not(feature = "debug-guards"))]
21 {
22 let _ = target;
23 None
24 }
25}
26
27#[inline]
28fn guard_payload_empty<T: ?Sized>() -> GuardPayload<T> {
29 guard_payload_from::<T>(None)
30}
31
32#[inline]
33fn guard_extract_target<T: ?Sized>(payload: GuardPayload<T>) -> Option<NonNull<T>> {
34 #[cfg(feature = "debug-guards")]
35 {
36 payload
37 }
38 #[cfg(not(feature = "debug-guards"))]
39 {
40 let _ = payload;
41 None
42 }
43}
44
45#[inline]
46fn guard_assert_target<T: ?Sized>(payload: GuardPayload<T>, target: *mut u8) {
47 #[cfg(feature = "debug-guards")]
48 {
49 if let Some(expected) = payload {
50 debug_assert_eq!(expected.as_ptr() as *mut u8, target);
51 }
52 }
53 #[cfg(not(feature = "debug-guards"))]
54 {
55 let _ = (payload, target);
56 }
57}
58
59enum RefState<T: ?Sized> {
60 Unset,
61 Ready(GuardPayload<T>),
62}
63
64impl<T: ?Sized> Copy for RefState<T> {}
65
66impl<T: ?Sized> Clone for RefState<T> {
67 fn clone(&self) -> Self {
68 *self
69 }
70}
71
72/// It is always safe to cast between a
73/// `Option<NonNull<T>>` and a `*mut T`
74/// because they are the exact same in memory
75#[inline(always)]
76fn nn_to_ptr<T: ?Sized>(nn: Ptr<T>) -> *mut T {
77 unsafe { core::mem::transmute(nn) }
78}
79
80/// A pointer that stores offsets instead of addresses, enabling movable self-referential structures.
81///
82/// Unlike regular pointers that become invalid when data moves, `SelfRef` stores the relative
83/// distance to its target. This offset remains valid regardless of where the containing structure
84/// is moved in memory - stack, heap, or anywhere else.
85///
86/// The magic happens through the offset type `I`: use `i8` for tiny 1-byte pointers with ±127 byte
87/// range, `i16` for 2-byte pointers with ±32KB range, or larger types for bigger structures.
88///
89/// ```rust
90/// use movable_ref::SelfRef;
91///
92/// struct Node {
93/// value: String,
94/// self_ref: SelfRef<String, i16>, // 2 bytes instead of 8
95/// }
96///
97/// impl Node {
98/// fn new(value: String) -> Self {
99/// let mut node = Self {
100/// value,
101/// self_ref: SelfRef::null(),
102/// };
103/// node.self_ref.set(&mut node.value).unwrap();
104/// node
105/// }
106/// }
107///
108/// // Works everywhere - stack, heap, vectors
109/// let mut node = Node::new("test".into());
110/// let boxed = Box::new(node);
111/// let mut vec = vec![*boxed];
112/// let base = &vec[0] as *const _ as *const u8;
113/// let value = unsafe { vec[0].self_ref.get_ref_from_base_unchecked(base) };
114/// ```
115///
116/// # Safety Considerations
117///
118/// `SelfRef` uses `unsafe` internally but provides safe setup methods. The main safety requirement
119/// is that once set, the relative positions of the pointer and target must not change. Moving
120/// the entire structure is always safe - it's only internal layout changes that cause issues.
121///
122/// Special care needed with packed structs: field reordering during drops can invalidate offsets.
123pub struct SelfRef<T: ?Sized + PointerRecomposition, I: Offset = isize>(
124 I,
125 MaybeUninit<T::Components>,
126 PhantomData<*mut T>,
127 RefState<T>,
128);
129
130// Ergonomics and ptr like impls
131
132impl<T: ?Sized + PointerRecomposition, I: Offset> Copy for SelfRef<T, I> {}
133impl<T: ?Sized + PointerRecomposition, I: Offset> Clone for SelfRef<T, I> {
134 fn clone(&self) -> Self {
135 *self
136 }
137}
138
139impl<T: ?Sized + PointerRecomposition, I: Offset> Eq for SelfRef<T, I> {}
140impl<T: ?Sized + PointerRecomposition, I: Offset> PartialEq for SelfRef<T, I> {
141 fn eq(&self, other: &Self) -> bool {
142 match (self.components_if_ready(), other.components_if_ready()) {
143 (None, None) => true,
144 (Some(lhs), Some(rhs)) => self.0 == other.0 && lhs == rhs,
145 _ => false,
146 }
147 }
148}
149
150impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I> {
151 /// Creates an unset relative pointer.
152 ///
153 /// This is the starting point for most `SelfRef` usage - create a null pointer,
154 /// then use `set()` to point it at your target data.
155 ///
156 /// # Returns
157 /// * `SelfRef<T, I>` - Pointer that must be initialised before use.
158 #[inline(always)]
159 pub fn null() -> Self {
160 Self(I::NULL, MaybeUninit::uninit(), PhantomData, RefState::Unset)
161 }
162
163 /// Checks if the pointer is unset.
164 ///
165 /// # Returns
166 /// * `bool` - `true` when the pointer has not been initialised.
167 #[inline(always)]
168 pub fn is_null(&self) -> bool {
169 self.0 == I::NULL
170 }
171}
172
173impl<T: ?Sized + PointerRecomposition, I: Offset> SelfRef<T, I> {
174 /// Returns `true` once the pointer metadata has been populated.
175 ///
176 /// # Returns
177 /// * `bool` - `true` when initialisation has completed.
178 #[inline]
179 pub fn is_ready(&self) -> bool {
180 matches!(self.3, RefState::Ready(_))
181 }
182
183 /// Provides the stored metadata when the pointer is initialised.
184 ///
185 /// # Returns
186 /// * `Option<T::Components>` - Metadata captured during initialisation.
187 #[inline]
188 pub fn components_if_ready(&self) -> Option<T::Components> {
189 match self.3 {
190 RefState::Ready(_) => Some(unsafe { self.components_unchecked() }),
191 RefState::Unset => None,
192 }
193 }
194
195 #[inline]
196 unsafe fn components_unchecked(&self) -> T::Components {
197 *self.1.assume_init_ref()
198 }
199
200 /// Returns the raw distance recorded for this pointer.
201 ///
202 /// # Returns
203 /// * `I` - Offset measured from this pointer to the target.
204 #[inline]
205 pub fn offset(&self) -> I {
206 self.0
207 }
208
209 /// Reconstructs a relative pointer from previously captured parts.
210 ///
211 /// # Parameters
212 /// * `offset` - Relative distance between pointer and target when captured.
213 /// * `components` - Metadata produced by [`PointerRecomposition::decompose`].
214 ///
215 /// # Returns
216 /// * `SelfRef<T, I>` - Pointer ready to be used at the current location.
217 #[inline]
218 pub fn from_parts(offset: I, components: T::Components) -> Self {
219 Self(
220 offset,
221 MaybeUninit::new(components),
222 PhantomData,
223 RefState::Ready(guard_payload_empty::<T>()),
224 )
225 }
226
227 /// Reconstructs a relative pointer and optionally tracks a known absolute target.
228 ///
229 /// The recorded pointer is only meaningful while the container remains at the
230 /// same address; moves invalidate the stored absolute pointer and trigger debug
231 /// assertions when the pointer is dereferenced.
232 ///
233 /// # Parameters
234 /// * `offset` - Relative distance between pointer and target when captured.
235 /// * `components` - Metadata produced by [`PointerRecomposition::decompose`].
236 /// * `target` - Optional absolute pointer retained for debug verification.
237 ///
238 /// # Returns
239 /// * `SelfRef<T, I>` - Pointer configured with optional debug metadata.
240 #[inline]
241 pub fn from_parts_with_target(
242 offset: I,
243 components: T::Components,
244 target: Option<NonNull<T>>,
245 ) -> Self {
246 Self(
247 offset,
248 MaybeUninit::new(components),
249 PhantomData,
250 RefState::Ready(guard_payload_from::<T>(target)),
251 )
252 }
253
254 /// Returns the stored offset and metadata when initialised.
255 ///
256 /// # Returns
257 /// * `Option<(I, T::Components)>` - Offset and metadata if the pointer is ready.
258 #[inline]
259 pub fn parts_if_ready(&self) -> Option<(I, T::Components)> {
260 self.components_if_ready()
261 .map(|components| (self.0, components))
262 }
263
264 /// Returns offset, metadata, and any recorded absolute pointer when initialised.
265 ///
266 /// # Returns
267 /// * `Option<(I, T::Components, Option<NonNull<T>>)>` - Captured parts used for reconstruction
268 /// along with the optional debug target.
269 #[inline]
270 pub fn parts_with_target_if_ready(&self) -> Option<(I, T::Components, Option<NonNull<T>>)> {
271 self.components_if_ready().map(|components| match self.3 {
272 RefState::Ready(payload) => (self.0, components, guard_extract_target::<T>(payload)),
273 RefState::Unset => unreachable!(),
274 })
275 }
276
277 /// Sets the pointer to target the given value.
278 ///
279 /// Computes the offset from this `SelfRef`'s location to the target value.
280 /// Returns an error if the distance is too large for the offset type `I`.
281 ///
282 /// This is the safe way to establish the self-reference - it validates that
283 /// the offset fits before storing it.
284 ///
285 /// ```rust
286 /// use movable_ref::SelfRef;
287 /// let mut data = "hello".to_string();
288 /// let mut ptr: SelfRef<String, i16> = SelfRef::null();
289 /// ptr.set(&mut data).unwrap(); // Now points to data
290 /// ```
291 ///
292 /// # Parameters
293 /// * `value` - Target to be referenced by the pointer.
294 ///
295 /// # Returns
296 /// * `Result<(), I::Error>` - `Ok` when the offset fits in `I`, otherwise the conversion error.
297 #[inline]
298 pub fn set(&mut self, value: &mut T) -> Result<(), I::Error> {
299 self.0 = I::sub(value as *mut T as _, self as *mut Self as _)?;
300 self.1 = MaybeUninit::new(T::decompose(value));
301 self.3 = RefState::Ready(guard_payload_empty::<T>());
302
303 Ok(())
304 }
305
306 /// Sets the pointer without bounds checking.
307 ///
308 /// Like `set()` but assumes the offset will fit in type `I`. Used when you've
309 /// already validated the distance or are reconstructing a known-good pointer.
310 ///
311 /// # Safety
312 ///
313 /// The offset between `value` and `self` must be representable in `I`.
314 /// `value` must not be null.
315 ///
316 /// # Parameters
317 /// * `value` - Raw pointer to the target value.
318 #[inline]
319 pub unsafe fn set_unchecked(&mut self, value: *mut T) {
320 debug_assert!(!value.is_null());
321 self.0 = I::sub_unchecked(value as _, self as *mut Self as _);
322 self.1 = MaybeUninit::new(T::decompose(&*value));
323 self.3 = RefState::Ready(guard_payload_empty::<T>());
324 }
325
326 /// Reconstructs the target pointer without null checking.
327 ///
328 /// # Safety
329 ///
330 /// The pointer must have been successfully set and the relative positions
331 /// of the pointer and target must not have changed since setting.
332 ///
333 /// # Returns
334 /// * `*mut T` - Raw pointer to the target.
335 #[inline]
336 unsafe fn as_raw_unchecked_impl(&mut self) -> *mut T {
337 debug_assert!(self.is_ready());
338 let base = self as *mut Self as *const u8;
339 let target = self.0.add(base);
340 let components = unsafe { self.components_unchecked() };
341 nn_to_ptr(T::recompose(NonNull::new(target), components))
342 }
343
344 /// Reconstructs the target as a mutable raw pointer.
345 ///
346 /// # Safety
347 ///
348 /// Same as `as_raw_unchecked_impl`.
349 ///
350 /// # Returns
351 /// * `*mut T` - Raw pointer to the target.
352 #[inline]
353 pub unsafe fn as_raw_unchecked(&mut self) -> *mut T {
354 self.as_raw_unchecked_impl()
355 }
356
357 /// Reconstructs the target as a `NonNull` pointer.
358 ///
359 /// # Safety
360 ///
361 /// Same as `as_raw_unchecked_impl`.
362 ///
363 /// # Returns
364 /// * `NonNull<T>` - Guaranteed non-null pointer to the target.
365 #[inline]
366 pub unsafe fn as_non_null_unchecked(&mut self) -> NonNull<T> {
367 debug_assert!(self.is_ready());
368 let base = self as *mut Self as *const u8;
369 let target = self.0.add(base);
370 let components = unsafe { self.components_unchecked() };
371 if let RefState::Ready(payload) = self.3 {
372 guard_assert_target::<T>(payload, target);
373 }
374 T::recompose(NonNull::new(target), components)
375 .unchecked_unwrap("Tried to use an unset relative pointer, this is UB in release mode!")
376 }
377
378 /// Reconstructs the target as an immutable reference.
379 ///
380 /// This is the most common way to access your self-referenced data.
381 ///
382 /// # Safety
383 ///
384 /// Same as `as_raw_unchecked_impl`. Standard reference aliasing rules apply.
385 ///
386 /// # Returns
387 /// * `&T` - Shared reference to the target.
388 #[inline]
389 pub unsafe fn as_ref_unchecked(&mut self) -> &T {
390 &*self.as_raw_unchecked_impl()
391 }
392
393 /// Reconstructs a shared reference using a container base pointer.
394 ///
395 /// # Safety
396 ///
397 /// * `base` must be the start address of the object that currently contains `self`.
398 /// * The pointer must have been established with `set` and the relative positions must
399 /// remain unchanged.
400 /// * No mutable reference to the target may exist for the lifetime of the returned reference.
401 ///
402 /// # Parameters
403 /// * `base` - Address of the owning container currently holding the pointer.
404 ///
405 /// # Returns
406 /// * `&'a T` - Shared reference resolved relative to `base`.
407 #[inline]
408 pub unsafe fn get_ref_from_base_unchecked<'a>(&self, base: *const u8) -> &'a T {
409 debug_assert!(self.is_ready());
410 let self_ptr = self as *const Self as *const u8;
411 let d_self = self_ptr.offset_from(base);
412 let at_self = base.wrapping_offset(d_self);
413 let components = unsafe { self.components_unchecked() };
414 let target = self.0.add(at_self);
415 if let RefState::Ready(payload) = self.3 {
416 guard_assert_target::<T>(payload, target);
417 }
418 let p = nn_to_ptr(T::recompose(NonNull::new(target), components));
419 &*p
420 }
421
422 /// Reconstructs a mutable reference using a container base pointer.
423 ///
424 /// # Safety
425 ///
426 /// * `base` must point to the start of the object that currently contains `self`.
427 /// * The pointer must have been initialised with `set` and the relative positions must
428 /// remain unchanged.
429 /// * The caller must guarantee unique access to the target for the lifetime of the
430 /// returned reference.
431 ///
432 /// # Parameters
433 /// * `base` - Address of the owning container currently holding the pointer.
434 ///
435 /// # Returns
436 /// * `&'a mut T` - Exclusive reference resolved relative to `base`.
437 #[inline]
438 pub unsafe fn get_mut_from_base_unchecked<'a>(&self, base: *mut u8) -> &'a mut T {
439 debug_assert!(self.is_ready());
440 let base_ptr = base.cast_const();
441 let self_ptr = self as *const Self as *const u8;
442 let d_self = self_ptr.offset_from(base_ptr);
443 let at_self = base_ptr.wrapping_offset(d_self);
444 let components = unsafe { self.components_unchecked() };
445 let target = self.0.add(at_self);
446 if let RefState::Ready(payload) = self.3 {
447 guard_assert_target::<T>(payload, target);
448 }
449 let p = nn_to_ptr(T::recompose(NonNull::new(target), components));
450 &mut *p
451 }
452
453 /// Reconstructs the target as a mutable reference.
454 ///
455 /// # Safety
456 ///
457 /// Same as `as_raw_unchecked_impl`. Standard reference aliasing rules apply.
458 ///
459 /// # Returns
460 /// * `&mut T` - Exclusive reference to the target.
461 #[inline]
462 pub unsafe fn as_mut_unchecked(&mut self) -> &mut T {
463 &mut *self.as_raw_unchecked()
464 }
465}
466
467impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I> {
468 /// Reconstructs the target as a raw pointer, returning null if unset.
469 ///
470 /// # Safety
471 ///
472 /// If the pointer was set, the relative positions must not have changed.
473 /// For most pointer types this is safe, but may be undefined behavior
474 /// for some exotic pointer representations.
475 ///
476 /// # Returns
477 /// * `*mut T` - Raw pointer to the target or null when unset.
478 #[inline]
479 pub unsafe fn as_raw(&mut self) -> *mut T {
480 nn_to_ptr(self.as_non_null())
481 }
482
483 /// Reconstructs the target as a `NonNull` pointer, returning `None` if unset.
484 ///
485 /// # Safety
486 ///
487 /// If the pointer was set, the relative positions must not have changed.
488 ///
489 /// # Returns
490 /// * `Option<NonNull<T>>` - Non-null pointer when initialised.
491 #[inline]
492 pub unsafe fn as_non_null(&mut self) -> Ptr<T> {
493 if !self.is_ready() {
494 return None;
495 }
496 let base = self as *mut Self as *const u8;
497 let target = self.0.add(base);
498 let components = unsafe { self.components_unchecked() };
499 if let RefState::Ready(payload) = self.3 {
500 guard_assert_target::<T>(payload, target);
501 }
502 T::recompose(NonNull::new(target), components)
503 }
504
505 /// Reconstructs the target as an immutable reference, returning `None` if unset.
506 ///
507 /// # Safety
508 ///
509 /// Standard reference aliasing rules apply. If the pointer was set,
510 /// the relative positions must not have changed.
511 ///
512 /// # Returns
513 /// * `Option<&T>` - Shared reference when initialised.
514 #[inline]
515 pub unsafe fn as_ref(&mut self) -> Option<&T> {
516 self.as_non_null().map(|ptr| unsafe { &*ptr.as_ptr() })
517 }
518
519 /// Reconstructs the target as a mutable reference, returning `None` if unset.
520 ///
521 /// # Safety
522 ///
523 /// Standard reference aliasing rules apply. If the pointer was set,
524 /// the relative positions must not have changed.
525 ///
526 /// # Returns
527 /// * `Option<&mut T>` - Exclusive reference when initialised.
528 #[inline]
529 pub unsafe fn as_mut(&mut self) -> Option<&mut T> {
530 self.as_non_null()
531 .map(|mut_ptr| unsafe { &mut *mut_ptr.as_ptr() })
532 }
533}