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}