movable-ref 0.1.0

A tool for building movable self-referential types
Documentation
  • Coverage
  • 100%
    22 out of 22 items documented4 out of 4 items with examples
  • Size
  • Source code size: 78.72 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 5.18 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Links
  • engali94/movable-ref
    61 2 3
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • engali94

movable-ref

Crates.io Documentation CI Ubuntu macOS Windows MSRV

A Rust library for offset based pointers that enable movable self-referential data structures.

The Problem

Standard Rust cannot create self-referential structures that can be moved in memory:

// This is impossible in safe Rust
struct SelfRef<'a> {
    data: String,
    ptr: &'a str,  // Cannot reference self.data
}

Existing solutions have many limitations:

  • Pin<Box<T>>: Requires heap allocation, prevents movement.
  • Rc<RefCell<T>>: Runtime overhead, not Send/Sync
  • ouroboros: Complex macros, limited flexibility.

The Solution

Offset pointers store offsets instead of absolute addresses, enabling self-referential structures that remain valid when moved:

use movable_ref::SelfRef;

struct Node {
    value: String,
    self_ref: SelfRef<String, i16>,  // 2-byte offset instead of 8-byte pointer
}

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
    }
    
    fn get_value(&self) -> &str {
        unsafe { self.self_ref.as_ref_unchecked() }
    }
}

// This works! The structure can be moved anywhere
let node = Node::new("Hello".to_string());
let boxed = Box::new(node);         // ✓ Moves to heap
let mut vec = Vec::new();
vec.push(*boxed);                   // ✓ Moves again
println!("{}", vec[0].get_value()); // ✓ Still works!

Why tether?

Offset pointers solve a fundamental limitation in Rust: creating efficient, movable self-referential data structures. While other solutions exist, tether provides:

  1. Embedded Systems Freidnly: Can run in very memory constrained devices.
  2. Movement freedom: Structures work on stack, heap, or anywhere unlike Pin
  3. True zero-cost abstraction: Zero to Minimal runtime overhead
  4. Memory efficiency: 1-8 bytes vs 8+ bytes for alternatives
  5. Simplicity: Straightforward API without complex macros

Perfect for performance-critical applications, embedded systems, and anywhere you need self-referential structures that can move.

Installation

Add to your Cargo.toml:

[dependencies]
movable-ref = "0.1.0"

Basic Usage

use movable_ref::SelfRef;

// 1. Create structure with null pointer
let mut data = MyStruct {
    value: "Hello".to_string(),
    ptr: SelfRef::null(),
};

// 2. Set the relative pointer
data.ptr.set(&mut data.value).unwrap();

// 3. Use it safely
let reference: &str = unsafe { data.ptr.as_ref_unchecked() };

Features

  • no_std: Works in embedded environments
  • nightly: Trait object support with nightly Rust
[dependencies]
movable-ref = { version = "0.1.0", features = ["no_std"] }

Performance Benchmarks

Run cargo bench to see these results on your machine:

🚀 Access Speed (lower = faster)

Direct Access:   329ps  (baseline)
SelfRef:         331ps  ⭐ FASTEST
Pin<Box<T>>:     365ps  (+10% slower)
Rc<RefCell<T>>:  429ps  (+30% slower)

💾 Memory Efficiency

SelfRef<T, i8>:   1 byte  (±127 byte range)
SelfRef<T, i16>:  2 bytes (±32KB range)  
SelfRef<T, i32>:  4 bytes (±2GB range)
*const T:         8 bytes (full address space)
Rc<RefCell<T>>:   8 bytes + heap allocation

Creation Speed

Direct:           19ns   (baseline)
SelfRef:          38ns   (+100% but still fastest)
Rc<RefCell<T>>:   40ns   
Pin<Box<T>>:      46ns   

🔄 Move Semantics

Direct move:      49ns   
Rc<RefCell<T>>:   50ns   (clone, not true move)
SelfRef move:     58ns   ⭐ __TRUE MOVE SEMANTICS__
Pin<Box<T>>:      N/A    (cannot move!)

Key Takeaways:

  • Zero-cost abstraction: SelfRef access is as fast as direct access
  • Memory efficient: 1-8 bytes vs 8+ bytes for alternatives
  • True movability: Unlike Pin<Box>, SelfRef can actually move
  • No runtime overhead: No borrow checking like Rc<RefCell>

Comparison with Alternatives

Solution Move Cost Memory Runtime Cost Complexity
SelfRef Zero 1-8 bytes Zero Low
Pin<Box<T>> Impossible 8+ bytes Allocation Medium
Rc<RefCell<T>> Cheap 16+ bytes Reference counting High
ouroboros Zero Varies Zero High

Safety

  • ⚠️ Uses unsafe for pointer dereferencing
  • ✅ Safe when structure layout doesn't change after pointer setup
  • ✅ Safe for moving entire structures
  • ✅ Extensively tested with Miri

Examples

Run the examples to see tether in action:

# Basic usage
cargo run --example basic_usage

# Performance benchmarks
cargo run --example performance

License

Licensed under MIT license.