1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*!
# 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.
```toml
# 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
```rust
# fn main() {
# use movable_ref::SelfRef;
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.
*/
extern crate core as std;
pub use SelfRefCell;
pub use *;
pub use *;
pub use *;
pub use *;