movable-ref
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
Existing solutions have many limitations:
Pin<Box<T>>
: Requires heap allocation, prevents movement.Rc<RefCell<T>>
: Runtime overhead, notSend
/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 SelfRef;
// This works! The structure can be moved anywhere
let node = new;
let boxed = Box new; // ✓ Moves to heap
let mut vec = Vec new;
vec.push; // ✓ Moves again
println!; // ✓ 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:
- Embedded Systems Freidnly: Can run in very memory constrained devices.
- Movement freedom: Structures work on stack, heap, or anywhere unlike
Pin
- True zero-cost abstraction: Zero to Minimal runtime overhead
- Memory efficiency: 1-8 bytes vs 8+ bytes for alternatives
- 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
:
[]
= "0.1.0"
Basic Usage
use SelfRef;
// 1. Create structure with null pointer
let mut data = MyStruct ;
// 2. Set the relative pointer
data.ptr.set.unwrap;
// 3. Use it safely
let reference: &str = unsafe ;
Features
no_std
: Works in embedded environmentsnightly
: Trait object support with nightly Rust
[]
= { = "0.1.0", = ["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
# Performance benchmarks
License
Licensed under MIT license.