+7
-7
Cargo.lock
+7
-7
Cargo.lock
···
4
5
[[package]]
6
name = "futures"
7
-
version = "0.0.1"
8
dependencies = [
9
"futures-combinators",
10
"futures-compat",
···
15
16
[[package]]
17
name = "futures-combinators"
18
-
version = "0.0.1"
19
dependencies = [
20
"futures-core",
21
"futures-util",
···
23
24
[[package]]
25
name = "futures-compat"
26
-
version = "0.0.1"
27
dependencies = [
28
"futures-core",
29
]
30
31
[[package]]
32
name = "futures-core"
33
-
version = "0.0.1"
34
35
[[package]]
36
name = "futures-derive"
37
-
version = "0.0.1"
38
dependencies = [
39
"proc-macro2",
40
"quote",
···
43
44
[[package]]
45
name = "futures-util"
46
-
version = "0.0.1"
47
dependencies = [
48
"futures-core",
49
]
50
51
[[package]]
52
name = "lifetime-guard"
53
-
version = "0.0.1"
54
55
[[package]]
56
name = "proc-macro2"
···
4
5
[[package]]
6
name = "futures"
7
+
version = "0.0.2"
8
dependencies = [
9
"futures-combinators",
10
"futures-compat",
···
15
16
[[package]]
17
name = "futures-combinators"
18
+
version = "0.0.2"
19
dependencies = [
20
"futures-core",
21
"futures-util",
···
23
24
[[package]]
25
name = "futures-compat"
26
+
version = "0.0.2"
27
dependencies = [
28
"futures-core",
29
]
30
31
[[package]]
32
name = "futures-core"
33
+
version = "0.0.2"
34
35
[[package]]
36
name = "futures-derive"
37
+
version = "0.0.2"
38
dependencies = [
39
"proc-macro2",
40
"quote",
···
43
44
[[package]]
45
name = "futures-util"
46
+
version = "0.0.2"
47
dependencies = [
48
"futures-core",
49
]
50
51
[[package]]
52
name = "lifetime-guard"
53
+
version = "0.0.2"
54
55
[[package]]
56
name = "proc-macro2"
+8
-8
Cargo.toml
+8
-8
Cargo.toml
···
3
members = [ "futures", "futures-core", "futures-combinators", "futures-compat", "futures-derive", "futures-util", "lifetime-guard"]
4
5
[workspace.package]
6
-
version = "0.0.1"
7
rust-version = "1.87"
8
edition = "2024"
9
license = "MIT OR Apache-2.0"
···
12
homepage = "https://github.com/AngleSideAngle/bcsc"
13
14
[workspace.dependencies]
15
-
futures = { path = "futures", version = "0.0.1" }
16
-
futures-combinators = { path = "futures-combinators", version = "0.0.1" }
17
-
futures-compat = { path = "futures-compat", version = "0.0.1" }
18
-
futures-core = { path = "futures-core", version = "0.0.1" }
19
-
futures-derive = { path = "futures-derive", version = "0.0.1" }
20
-
futures-util = { path = "futures-util", version = "0.0.1" }
21
-
lifetime-guard = { path = "lifetime-guard", version = "0.0.1" }
···
3
members = [ "futures", "futures-core", "futures-combinators", "futures-compat", "futures-derive", "futures-util", "lifetime-guard"]
4
5
[workspace.package]
6
+
version = "0.0.2"
7
rust-version = "1.87"
8
edition = "2024"
9
license = "MIT OR Apache-2.0"
···
12
homepage = "https://github.com/AngleSideAngle/bcsc"
13
14
[workspace.dependencies]
15
+
futures = { path = "futures", version = "0.0.2" }
16
+
futures-combinators = { path = "futures-combinators", version = "0.0.2" }
17
+
futures-compat = { path = "futures-compat", version = "0.0.2" }
18
+
futures-core = { path = "futures-core", version = "0.0.2" }
19
+
futures-derive = { path = "futures-derive", version = "0.0.2" }
20
+
futures-util = { path = "futures-util", version = "0.0.2" }
21
+
lifetime-guard = { path = "lifetime-guard", version = "0.0.2" }
+5
-2
lifetime-guard/README.md
+5
-2
lifetime-guard/README.md
···
13
let weak = pin::pin!(RefGuard::new());
14
{
15
let strong = pin::pin!(ValueGuard::new(0));
16
-
strong.as_ref().registration().register(weak.as_ref());
17
18
assert_eq!(strong.get(), 0);
19
assert_eq!(weak.get(), Some(0));
···
28
# Safety
29
30
You *may not* leak any instance of either `ValueGuard` or `RefGuard` to the
31
-
stack using `mem::forget()` or any other mechanism that causes thier
32
contents to be overwritten without `Drop::drop()` running.
33
Doing so creates unsoundness that likely will lead to dereferencing a null
34
pointer.
···
42
methods including `Box::leak()` because heap allocated data will never be
43
overwritten if it is never freed.
44
···
13
let weak = pin::pin!(RefGuard::new());
14
{
15
let strong = pin::pin!(ValueGuard::new(0));
16
+
weak.as_ref().register(strong.as_ref());
17
18
assert_eq!(strong.get(), 0);
19
assert_eq!(weak.get(), Some(0));
···
28
# Safety
29
30
You *may not* leak any instance of either `ValueGuard` or `RefGuard` to the
31
+
stack using `mem::forget()` or any other mechanism that causes their
32
contents to be overwritten without `Drop::drop()` running.
33
Doing so creates unsoundness that likely will lead to dereferencing a null
34
pointer.
···
42
methods including `Box::leak()` because heap allocated data will never be
43
overwritten if it is never freed.
44
45
+
The test cases for this library have been verified to not exhibit undefined
46
+
behavior using [miri](https://github.com/rust-lang/miri).
47
+
+38
-55
lifetime-guard/src/lib.rs
+38
-55
lifetime-guard/src/lib.rs
···
3
use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
4
5
/// Strong guard for granting read access to a single interior mutable value to
6
-
/// `RefGuard`.
7
///
8
/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
9
/// to a single `Rc` and `Weak` pair, but notably does not require heap
10
-
/// allocation. `ValueGuard::registration` creates a `GuardRegistration`, which
11
-
/// provides a movable wrapper for safety creating the circular references
12
-
/// between two pinned self referential structs.
13
///
14
/// # Safety
15
///
···
47
}
48
}
49
50
-
/// Returns a `GuardRegistration`, which can be used to safety link `Self`
51
-
/// to a `RefGuard`.
52
-
#[inline]
53
-
pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
54
-
GuardRegistration { value_guard: self }
55
-
}
56
-
57
/// Sets the internal value stored by `Self`.
58
#[inline]
59
pub fn set(&self, value: T) {
···
86
87
/// Weak guard for acquiring read only access to a `ValueGuard`'s value.
88
///
89
/// # Safety
90
///
91
/// This struct *must* not be leaked to the stack using `mem::forget` or any
···
111
_marker: PhantomPinned,
112
}
113
}
114
}
115
116
/// Helper function to invalidate a `RefGuard`'s `ValueGuard` reference
···
146
}
147
}
148
149
-
/// Safe api for creating self reference between a pinned `ValueGuard` and
150
-
/// `RefGuard` pair.
151
-
///
152
-
/// This can be acquired with
153
-
/// [`ValueGuard::registration()`](ValueGuard::registration).
154
-
pub struct GuardRegistration<'a, T> {
155
-
value_guard: Pin<&'a ValueGuard<T>>,
156
-
}
157
-
158
-
impl<'a, T> GuardRegistration<'a, T> {
159
-
/// Binds a provided `slot` to the `self.value_guard`.
160
-
///
161
-
/// This means they will reference each other, and will invalidate their
162
-
/// references to each other when dropped.
163
-
///
164
-
/// This method also invalidates the existing references held by the
165
-
/// now-replaced referencees of `slot` and `self.value_guard` to avoid
166
-
/// dangling pointers.
167
-
pub fn register(self, slot: Pin<&'a RefGuard<T>>) {
168
-
// replace slot's value guard with reference to self.value_guard
169
-
// and invalidate slot's old value guard if it exists
170
-
if let Some(old_guard) = slot
171
-
.value_guard
172
-
.replace(Some(self.value_guard.get_ref().into()))
173
-
{
174
-
invalidate_value_guard(old_guard);
175
-
}
176
-
177
-
// replace self.value_guard's ref guard with reference to slot
178
-
// and invalidate self.value_guard's old ref guard if it exists
179
-
if let Some(old_guard) = self
180
-
.value_guard
181
-
.ref_guard
182
-
.replace(Some(slot.get_ref().into()))
183
-
{
184
-
invalidate_ref_guard(old_guard);
185
-
}
186
-
}
187
-
}
188
-
189
#[cfg(test)]
190
mod test {
191
use std::{mem, pin};
···
197
let weak = pin::pin!(RefGuard::new());
198
{
199
let strong = pin::pin!(ValueGuard::new(2));
200
-
strong.as_ref().registration().register(weak.as_ref());
201
202
assert_eq!(strong.get(), 2);
203
assert_eq!(weak.get(), Some(2));
···
216
let weak2 = pin::pin!(RefGuard::new());
217
{
218
let strong = pin::pin!(ValueGuard::new(2));
219
-
strong.as_ref().registration().register(weak1.as_ref());
220
221
assert_eq!(strong.get(), 2);
222
assert_eq!(weak1.get(), Some(2));
···
226
assert_eq!(weak1.get(), Some(3));
227
228
// register next ptr, should invalidate previous weak ref (weak1)
229
-
strong.as_ref().registration().register(weak2.as_ref());
230
assert_eq!(weak1.get(), None);
231
assert_eq!(weak1.value_guard.get(), None);
232
···
247
fn safe_leak() {
248
let strong = Box::pin(ValueGuard::new(10));
249
let weak = pin::pin!(RefGuard::new());
250
-
strong.as_ref().registration().register(weak.as_ref());
251
252
// strong is now a ValueGuard on the heap that will never be freed
253
// this is sound because it will never be overwritten
···
3
use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
4
5
/// Strong guard for granting read access to a single interior mutable value to
6
+
/// [`RefGuard`](RefGuard).
7
///
8
/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
9
/// to a single `Rc` and `Weak` pair, but notably does not require heap
10
+
/// allocation.
11
///
12
/// # Safety
13
///
···
45
}
46
}
47
48
/// Sets the internal value stored by `Self`.
49
#[inline]
50
pub fn set(&self, value: T) {
···
77
78
/// Weak guard for acquiring read only access to a `ValueGuard`'s value.
79
///
80
+
/// Provides [`WeakGuard::register()`](Self::register) to register a `ValueGuard`
81
+
/// to `Self` and vice versa.
82
+
///
83
/// # Safety
84
///
85
/// This struct *must* not be leaked to the stack using `mem::forget` or any
···
105
_marker: PhantomPinned,
106
}
107
}
108
+
109
+
/// Binds a pinned `value_guard` to `self`.
110
+
///
111
+
/// This means they will reference each other, and will invalidate their
112
+
/// references to each other when dropped.
113
+
///
114
+
/// This method also invalidates the existing references held by the
115
+
/// now-replaced referencees of `self` and `value_guard` to avoid
116
+
/// dangling pointers.
117
+
pub fn register<'a>(
118
+
self: Pin<&'a RefGuard<T>>,
119
+
value_guard: Pin<&'a ValueGuard<T>>,
120
+
) {
121
+
// replace input value_guard's ref guard with reference to self
122
+
// and invalidate the old ref guard guard if it exists
123
+
if let Some(old_guard) =
124
+
value_guard.ref_guard.replace(Some(self.get_ref().into()))
125
+
{
126
+
invalidate_ref_guard(old_guard);
127
+
}
128
+
129
+
// replace self's value guard with reference to input value_guard
130
+
// and invalidate self.value_guard's old ref guard if it exists
131
+
if let Some(old_guard) =
132
+
self.value_guard.replace(Some(value_guard.get_ref().into()))
133
+
{
134
+
invalidate_value_guard(old_guard);
135
+
}
136
+
}
137
}
138
139
/// Helper function to invalidate a `RefGuard`'s `ValueGuard` reference
···
169
}
170
}
171
172
#[cfg(test)]
173
mod test {
174
use std::{mem, pin};
···
180
let weak = pin::pin!(RefGuard::new());
181
{
182
let strong = pin::pin!(ValueGuard::new(2));
183
+
weak.as_ref().register(strong.as_ref());
184
185
assert_eq!(strong.get(), 2);
186
assert_eq!(weak.get(), Some(2));
···
199
let weak2 = pin::pin!(RefGuard::new());
200
{
201
let strong = pin::pin!(ValueGuard::new(2));
202
+
weak1.as_ref().register(strong.as_ref());
203
204
assert_eq!(strong.get(), 2);
205
assert_eq!(weak1.get(), Some(2));
···
209
assert_eq!(weak1.get(), Some(3));
210
211
// register next ptr, should invalidate previous weak ref (weak1)
212
+
weak2.as_ref().register(strong.as_ref());
213
assert_eq!(weak1.get(), None);
214
assert_eq!(weak1.value_guard.get(), None);
215
···
230
fn safe_leak() {
231
let strong = Box::pin(ValueGuard::new(10));
232
let weak = pin::pin!(RefGuard::new());
233
+
weak.as_ref().register(strong.as_ref());
234
235
// strong is now a ValueGuard on the heap that will never be freed
236
// this is sound because it will never be overwritten