Crate movable_ref

Crate movable_ref 

Source
Expand description

§tether

tether is a library for offset-based pointers, which can be used to create movable self-referential types. Ituses an offset and its current location to calculate where it points to.

§Safety

See the SelfRef type documentation for safety information.

§Features

§no_std

This crate is no_std compatible. Disable the std feature to use without the standard library.

# For no_std environments (embedded systems, etc.)
[dependencies]
movable-ref = { version = "0.1.0", default-features = false }

# For std environments (default)
[dependencies]
movable-ref = "0.1.0"

§Example

Consider the memory segment below:

[.., 0x3a, 0x10, 0x02, 0xe4, 0x2b ..]

Where 0x3a has address 0xff304050 (32-bit system) and 0x2b has address 0xff304054.

If we have a 1-byte relative pointer (SelfRef<_, i8>) at address 0xff304052, then that relative pointer points to 0x2b because its address 0xff304052 plus its offset 0x02 equals 0xff304054.

Three key properties emerge:

  1. It only took 1 byte to point to another value
  2. A relative pointer can only access nearby memory
  3. If both the relative pointer and pointee move together, the relative pointer remains valid

The third property enables movable self-referential structures.

The type SelfRef<T, I> is a relative pointer where T is the target type and I is the offset storage type. In practice, you can ignore I (defaulted to isize) as it covers most use cases. For size optimization, use any type implementing Delta: i8, i16, i32, i64, i128, isize.

The tradeoff: smaller offset types reduce addressable range. isize covers at least half of addressable memory. For self-referential structures, choose an offset type whose range exceeds your structure size: std::mem::size_of::<YourStruct>() <= I::MAX.

Note: Unsized types require additional considerations.

§Self-Referential Type Example

struct SelfRefStruct {
    value: (String, u32),
    ptr: SelfRef<String, i8>
}

impl SelfRefStruct {
    pub fn new(s: String, i: u32) -> Self {
        let mut this = Self {
            value: (s, i),
            ptr: SelfRef::null()
        };

        this.ptr.set(&mut this.value.0).unwrap();
        this
    }

    pub fn fst(&mut self) -> &str {
        let base = self as *const _ as *const u8;
        unsafe { self.ptr.get_ref_from_base_unchecked(base) }
    }

    pub fn snd(&self) -> u32 {
        self.value.1
    }
}

let mut s = SelfRefStruct::new("Hello World".into(), 10);

assert_eq!(s.fst(), "Hello World");
assert_eq!(s.snd(), 10);

let mut s = Box::new(s); // Force a move - relative pointers work on the heap

assert_eq!(s.fst(), "Hello World");
assert_eq!(s.snd(), 10);

§Pattern Analysis

The example demonstrates the standard pattern for safe movable self-referential types:

Structure Definition: Contains data and a relative pointer. No lifetimes are used as they would either prevent movement or create unresolvable constraints.

Initialization Pattern: Create the object with SelfRef::null(), then immediately set the pointer using SelfRef::set(). Unwrapping provides immediate feedback if the offset range is insufficient.

Movement Safety: Once set, the structure can be moved safely because relative pointers maintain their offset relationship regardless of absolute position.

Access Safety: SelfRef::as_ref_unchecked() is safe when the pointer cannot be invalidated - which occurs when direct pointer modification is impossible and field offsets remain constant after initialization.

§Failure Modes

  • Calling unchecked APIs such as SelfRef::get_ref_from_base_unchecked before initialisation is undefined behaviour; prefer the safe SelfRefCell::try_get wrappers to detect readiness.
  • When the optional debug-guards feature is enabled, absolute pointers captured through SelfRef::from_parts_with_target or [SelfRef::guard] must only be used while the owning structure remains at a fixed address. Moving the container without refreshing these guards will trigger debug assertions.

Modules§

impls
Implementations of MetaData trait for various types
traits
Traits for metadata extraction and composition
unreachable
Module for handling unreachable code

Structs§

IntegerOffsetError
An error type for when an integer offset cannot be stored
SelfRef
A pointer that stores offsets instead of addresses, enabling movable self-referential structures.
SelfRefCell
Container that provides safe access to a self-referenced value.

Traits§

Nullable
A Delta type that has a null/zero value.
Offset
Trait for types that can represent pointer differences.
PointerRecomposition
The bridge that makes SelfRef work with any type, sized or unsized.

Type Aliases§

Ptr
A nullable pointer, using NonNull<T>