Struct SelfRef

Source
pub struct SelfRef<T: ?Sized + PointerRecomposition, I: Offset = isize>(/* private fields */);
Expand description

A pointer that stores offsets instead of addresses, enabling movable self-referential structures.

Unlike regular pointers that become invalid when data moves, SelfRef stores the relative distance to its target. This offset remains valid regardless of where the containing structure is moved in memory - stack, heap, or anywhere else.

The magic happens through the offset type I: use i8 for tiny 1-byte pointers with ±127 byte range, i16 for 2-byte pointers with ±32KB range, or larger types for bigger structures.

use movable_ref::SelfRef;

struct Node {
    value: String,
    self_ref: SelfRef<String, i16>,  // 2 bytes instead of 8
}

impl Node {
    fn new(value: String) -> Self {
        let mut node = Self {
            value,
            self_ref: SelfRef::null(),
        };
        node.self_ref.set(&mut node.value).unwrap();
        node
    }
}

// Works everywhere - stack, heap, vectors
let node = Node::new("test".into());
let boxed = Box::new(node);              // ✓ Moves to heap
let mut vec = vec![*boxed];              // ✓ Moves again  
let value = unsafe { vec[0].self_ref.as_ref_unchecked() };  // ✓ Still valid

§Safety Considerations

SelfRef uses unsafe internally but provides safe setup methods. The main safety requirement is that once set, the relative positions of the pointer and target must not change. Moving the entire structure is always safe - it’s only internal layout changes that cause issues.

Special care needed with packed structs: field reordering during drops can invalidate offsets.

Using NonZero* offset types with self-pointing (zero offset) is undefined behavior.

Implementations§

Source§

impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I>

Source

pub fn null() -> Self

Creates an unset relative pointer.

This is the starting point for most SelfRef usage - create a null pointer, then use set() to point it at your target data.

Source

pub fn is_null(&self) -> bool

Checks if the pointer is unset.

Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> SelfRef<T, I>

Source

pub fn set(&mut self, value: &mut T) -> Result<(), I::Error>

Sets the pointer to target the given value.

Computes the offset from this SelfRef’s location to the target value. Returns an error if the distance is too large for the offset type I.

This is the safe way to establish the self-reference - it validates that the offset fits before storing it.

use movable_ref::SelfRef;
let mut data = "hello".to_string();
let mut ptr: SelfRef<String, i16> = SelfRef::null();
ptr.set(&mut data).unwrap();  // Now points to data
Source

pub unsafe fn set_unchecked(&mut self, value: *mut T)

Sets the pointer without bounds checking.

Like set() but assumes the offset will fit in type I. Used when you’ve already validated the distance or are reconstructing a known-good pointer.

§Safety

The offset between value and self must be representable in I. value must not be null.

Source

pub unsafe fn as_raw_unchecked(&mut self) -> *mut T

Reconstructs the target as a mutable raw pointer.

§Safety

Same as as_raw_unchecked_impl.

Source

pub unsafe fn as_non_null_unchecked(&mut self) -> NonNull<T>

Reconstructs the target as a NonNull pointer.

§Safety

Same as as_raw_unchecked_impl.

Source

pub unsafe fn as_ref_unchecked(&self) -> &T

Reconstructs the target as an immutable reference.

This is the most common way to access your self-referenced data.

§Safety

Same as as_raw_unchecked_impl. Standard reference aliasing rules apply.

Source

pub unsafe fn as_mut_unchecked(&mut self) -> &mut T

Reconstructs the target as a mutable reference.

§Safety

Same as as_raw_unchecked_impl. Standard reference aliasing rules apply.

Source§

impl<T: ?Sized + PointerRecomposition, I: Nullable> SelfRef<T, I>

Source

pub unsafe fn as_raw(&mut self) -> *mut T

Reconstructs the target as a raw pointer, returning null if unset.

§Safety

If the pointer was set, the relative positions must not have changed. For most pointer types this is safe, but may be undefined behavior for some exotic pointer representations.

Source

pub unsafe fn as_non_null(&mut self) -> Ptr<T>

Reconstructs the target as a NonNull pointer, returning None if unset.

§Safety

If the pointer was set, the relative positions must not have changed.

Source

pub unsafe fn as_ref(&self) -> Option<&T>

Reconstructs the target as an immutable reference, returning None if unset.

§Safety

Standard reference aliasing rules apply. If the pointer was set, the relative positions must not have changed.

Source

pub unsafe fn as_mut(&mut self) -> Option<&mut T>

Reconstructs the target as a mutable reference, returning None if unset.

§Safety

Standard reference aliasing rules apply. If the pointer was set, the relative positions must not have changed.

Trait Implementations§

Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> Clone for SelfRef<T, I>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

const fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: ?Sized + PointerRecomposition, I: Debug + Offset> Debug for SelfRef<T, I>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> From<I> for SelfRef<T, I>

Convert an offset into a SelfRef

Source§

fn from(i: I) -> Self

Converts to this type from the input type.
Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> PartialEq for SelfRef<T, I>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: ?Sized + PointerRecomposition, I: Debug + Offset> Pointer for SelfRef<T, I>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> Copy for SelfRef<T, I>

Source§

impl<T: ?Sized + PointerRecomposition, I: Offset> Eq for SelfRef<T, I>

Auto Trait Implementations§

§

impl<T, I> Freeze for SelfRef<T, I>

§

impl<T, I> RefUnwindSafe for SelfRef<T, I>

§

impl<T, I = isize> !Send for SelfRef<T, I>

§

impl<T, I = isize> !Sync for SelfRef<T, I>

§

impl<T, I> Unpin for SelfRef<T, I>

§

impl<T, I> UnwindSafe for SelfRef<T, I>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.