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
12/// It is always safe to cast between a
13/// `Option<NonNull<T>>` and a `*mut T`
14/// because they are the exact same in memory
15#[inline(always)]
16fn nn_to_ptr<T: ?Sized>(nn: Ptr<T>) -> *mut T {
17    unsafe { std::mem::transmute(nn) }
18}
19
20/// A pointer that stores offsets instead of addresses, enabling movable self-referential structures.
21///
22/// Unlike regular pointers that become invalid when data moves, `SelfRef` stores the relative
23/// distance to its target. This offset remains valid regardless of where the containing structure
24/// is moved in memory - stack, heap, or anywhere else.
25///
26/// The magic happens through the offset type `I`: use `i8` for tiny 1-byte pointers with ±127 byte
27/// range, `i16` for 2-byte pointers with ±32KB range, or larger types for bigger structures.
28///
29/// ```rust
30/// use movable_ref::SelfRef;
31///
32/// struct Node {
33///     value: String,
34///     self_ref: SelfRef<String, i16>,  // 2 bytes instead of 8
35/// }
36///
37/// impl Node {
38///     fn new(value: String) -> Self {
39///         let mut node = Self {
40///             value,
41///             self_ref: SelfRef::null(),
42///         };
43///         node.self_ref.set(&mut node.value).unwrap();
44///         node
45///     }
46/// }
47///
48/// // Works everywhere - stack, heap, vectors
49/// let node = Node::new("test".into());
50/// let boxed = Box::new(node);              // ✓ Moves to heap
51/// let mut vec = vec![*boxed];              // ✓ Moves again  
52/// let value = unsafe { vec[0].self_ref.as_ref_unchecked() };  // ✓ Still valid
53/// ```
54///
55/// # Safety Considerations
56///
57/// `SelfRef` uses `unsafe` internally but provides safe setup methods. The main safety requirement
58/// is that once set, the relative positions of the pointer and target must not change. Moving
59/// the entire structure is always safe - it's only internal layout changes that cause issues.
60///
61/// Special care needed with packed structs: field reordering during drops can invalidate offsets.
62///
63/// Using `NonZero*` offset types with self-pointing (zero offset) is undefined behavior.
64pub struct SelfRef<T: ?Sized + PointerRecomposition, I: Offset = isize>(
65    I,
66    MaybeUninit<T::Components>,
67    PhantomData<*mut T>,
68);
69
70// Ergonomics and ptr like impls
71
72impl<T: ?Sized + PointerRecomposition, I: Offset> Copy for SelfRef<T, I> {}
73impl<T: ?Sized + PointerRecomposition, I: Offset> Clone for SelfRef<T, I> {
74    fn clone(&self) -> Self {
75        *self
76    }
77}
78
79impl<T: ?Sized + PointerRecomposition, I: Offset> Eq for SelfRef<T, I> {}
80impl<T: ?Sized + PointerRecomposition, I: Offset> PartialEq for SelfRef<T, I> {
81    fn eq(&self, other: &Self) -> bool {
82        std::ptr::eq(self, other)
83    }
84}
85
86/// Convert an offset into a `SelfRef`
87impl<T: ?Sized + PointerRecomposition, I: Offset> From<I> for SelfRef<T, I> {
88    fn from(i: I) -> Self {
89        Self(i, MaybeUninit::uninit(), PhantomData)
90    }
91}
92
93impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I> {
94    /// Creates an unset relative pointer.
95    ///
96    /// This is the starting point for most `SelfRef` usage - create a null pointer,
97    /// then use `set()` to point it at your target data.
98    #[inline(always)]
99    pub fn null() -> Self {
100        Self(I::NULL, MaybeUninit::uninit(), PhantomData)
101    }
102
103    /// Checks if the pointer is unset.
104    #[inline(always)]
105    pub fn is_null(&self) -> bool {
106        self.0 == I::NULL
107    }
108}
109
110impl<T: ?Sized + PointerRecomposition, I: Offset> SelfRef<T, I> {
111    /// Sets the pointer to target the given value.
112    ///
113    /// Computes the offset from this `SelfRef`'s location to the target value.
114    /// Returns an error if the distance is too large for the offset type `I`.
115    ///
116    /// This is the safe way to establish the self-reference - it validates that
117    /// the offset fits before storing it.
118    ///
119    /// ```rust
120    /// use movable_ref::SelfRef;
121    /// let mut data = "hello".to_string();
122    /// let mut ptr: SelfRef<String, i16> = SelfRef::null();
123    /// ptr.set(&mut data).unwrap();  // Now points to data
124    /// ```
125    #[inline]
126    pub fn set(&mut self, value: &mut T) -> Result<(), I::Error> {
127        self.0 = I::sub(value as *mut T as _, self as *mut Self as _)?;
128        self.1 = MaybeUninit::new(T::decompose(value));
129
130        Ok(())
131    }
132
133    /// Sets the pointer without bounds checking.
134    ///
135    /// Like `set()` but assumes the offset will fit in type `I`. Used when you've
136    /// already validated the distance or are reconstructing a known-good pointer.
137    ///
138    /// # Safety
139    ///
140    /// The offset between `value` and `self` must be representable in `I`.
141    /// `value` must not be null.
142    #[inline]
143    pub unsafe fn set_unchecked(&mut self, value: *mut T) {
144        self.0 = I::sub_unchecked(value as _, self as *mut Self as _);
145        self.1 = MaybeUninit::new(T::decompose(&*value));
146    }
147
148    /// Reconstructs the target pointer without null checking.
149    ///
150    /// # Safety
151    ///
152    /// The pointer must have been successfully set and the relative positions
153    /// of the pointer and target must not have changed since setting.
154    #[inline]
155    unsafe fn as_raw_unchecked_impl(&self) -> *const T {
156        nn_to_ptr(T::recompose(
157            NonNull::new(self.0.add(self as *const Self as *const u8)),
158            self.1.assume_init(),
159        ))
160    }
161
162    /// Reconstructs the target as a mutable raw pointer.
163    ///
164    /// # Safety
165    ///
166    /// Same as `as_raw_unchecked_impl`.
167    #[inline]
168    pub unsafe fn as_raw_unchecked(&mut self) -> *mut T {
169        self.as_raw_unchecked_impl() as _
170    }
171
172    /// Reconstructs the target as a `NonNull` pointer.
173    ///
174    /// # Safety
175    ///
176    /// Same as `as_raw_unchecked_impl`.
177    #[inline]
178    pub unsafe fn as_non_null_unchecked(&mut self) -> NonNull<T> {
179        T::recompose(
180            NonNull::new(self.0.add(self as *mut Self as *mut u8)),
181            self.1.assume_init(),
182        )
183        .unchecked_unwrap("Tried to use an unset relative pointer, this is UB in release mode!")
184    }
185
186    /// Reconstructs the target as an immutable reference.
187    ///
188    /// This is the most common way to access your self-referenced data.
189    ///
190    /// # Safety
191    ///
192    /// Same as `as_raw_unchecked_impl`. Standard reference aliasing rules apply.
193    #[inline]
194    pub unsafe fn as_ref_unchecked(&self) -> &T {
195        &*self.as_raw_unchecked_impl()
196    }
197
198    /// Reconstructs the target as a mutable reference.
199    ///
200    /// # Safety
201    ///
202    /// Same as `as_raw_unchecked_impl`. Standard reference aliasing rules apply.
203    #[inline]
204    pub unsafe fn as_mut_unchecked(&mut self) -> &mut T {
205        &mut *self.as_raw_unchecked()
206    }
207}
208
209macro_rules! as_non_null_impl {
210    ($self:ident) => {
211        if $self.is_null() {
212            None
213        } else {
214            T::recompose(
215                NonNull::new($self.0.add($self as *const Self as *const u8)),
216                $self.1.assume_init(),
217            )
218        }
219    };
220}
221
222impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I> {
223    /// Reconstructs the target as a raw pointer, returning null if unset.
224    ///
225    /// # Safety
226    ///
227    /// If the pointer was set, the relative positions must not have changed.
228    /// For most pointer types this is safe, but may be undefined behavior
229    /// for some exotic pointer representations.
230    #[inline]
231    pub unsafe fn as_raw(&mut self) -> *mut T {
232        nn_to_ptr(self.as_non_null())
233    }
234
235    /// Reconstructs the target as a `NonNull` pointer, returning `None` if unset.
236    ///
237    /// # Safety
238    ///
239    /// If the pointer was set, the relative positions must not have changed.
240    #[inline]
241    pub unsafe fn as_non_null(&mut self) -> Ptr<T> {
242        as_non_null_impl!(self)
243    }
244
245    /// Reconstructs the target as an immutable reference, returning `None` if unset.
246    ///
247    /// # Safety
248    ///
249    /// Standard reference aliasing rules apply. If the pointer was set,
250    /// the relative positions must not have changed.
251    #[inline]
252    pub unsafe fn as_ref(&self) -> Option<&T> {
253        Some(&*as_non_null_impl!(self)?.as_ptr())
254    }
255
256    /// Reconstructs the target as a mutable reference, returning `None` if unset.
257    ///
258    /// # Safety
259    ///
260    /// Standard reference aliasing rules apply. If the pointer was set,
261    /// the relative positions must not have changed.
262    #[inline]
263    pub unsafe fn as_mut(&mut self) -> Option<&mut T> {
264        Some(&mut *self.as_non_null()?.as_ptr())
265    }
266}