+45
-66
lifetime-guard/src/lib.rs
+45
-66
lifetime-guard/src/lib.rs
···
1
1
/// Unsound Drop based guard API
2
2
use std::{
3
3
cell::Cell,
4
-
mem,
5
-
pin::{Pin, pin},
6
-
ptr::{self, NonNull, dangling},
4
+
marker::PhantomPinned,
5
+
pin::Pin,
6
+
ptr::{self},
7
7
};
8
8
9
-
/// must not outlive strong guard
10
-
///
11
-
/// enforces strong guard doesn't move with ptr
12
-
pub struct WeakGuard<'weak, T> {
13
-
strong: Option<&'weak StrongGuard<'weak, T>>,
14
-
}
15
-
16
-
impl<'weak, T> WeakGuard<'weak, T> {
17
-
pub fn register_strong(&mut self, weak: &'weak T) {
18
-
self.strong = Some(weak);
19
-
}
20
-
}
21
-
22
-
impl<'weak, T> Drop for WeakGuard<'weak, StrongGuard<'weak, T>> {
23
-
fn drop(&mut self) {
24
-
// self.weak.
25
-
}
26
-
}
27
-
28
-
/// outlives strong guard
29
-
pub struct StrongGuard<'weak, T> {
30
-
strong: *const WeakGuard<'weak, T>,
31
-
}
32
-
33
-
// wakers must outlive 'task
34
-
impl<'weak, T> StrongGuard<'weak, T> {
35
-
pub fn new(strong: *const WeakGuard<'weak, T>) -> Self {
36
-
Self {
37
-
strong: task.into(),
38
-
}
39
-
}
40
-
}
41
-
42
-
// pub struct GuardRegistration<'weak, T> {
43
-
// task: &'weak StrongGuard<'weak, T>, // valid for all of 'weak
44
-
// }
45
-
46
-
// impl<'weak> GuardRegistration<'weak> {
47
-
// // slot is valid for all 'weak
48
-
// pub fn register(self, slot: &'weak mut StrongGuard<'weak>) {
49
-
// // Cast from 'weak to 'static
50
-
// //
51
-
// // # Safety
52
-
// //
53
-
// // This is safe because the drop guard guarantees that the task ptr (which lives for static)
54
-
// // becomes null when the wake is dropped, ensuring the dangling pointer is never dereferenced.
55
-
// let dangling_task = unsafe {
56
-
// mem::transmute::<
57
-
// &'weak dyn StrongGuard<'weak>,
58
-
// *const dyn StrongGuard<'weak>,
59
-
// >(self.task)
60
-
// };
61
-
// slot.strong = dangling_task;
62
-
63
-
// (*self.task).register_waker(slot);
64
-
// }
65
-
// }
66
-
67
9
pub struct ValueGuard<T> {
68
10
data: T,
69
11
ref_guard: Cell<*const RefGuard<T>>,
12
+
_marker: PhantomPinned,
70
13
}
71
14
72
15
impl<T> ValueGuard<T> {
···
74
17
Self {
75
18
data,
76
19
ref_guard: Cell::new(ptr::null()),
20
+
_marker: PhantomPinned,
77
21
}
22
+
}
23
+
24
+
pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
25
+
GuardRegistration { value_guard: self }
78
26
}
79
27
80
28
pub fn set(&mut self, value: T) {
···
101
49
102
50
pub struct RefGuard<T> {
103
51
value_guard: Cell<*const ValueGuard<T>>,
52
+
_marker: PhantomPinned,
104
53
}
105
54
106
55
impl<T> RefGuard<T> {
107
56
pub fn new() -> Self {
108
57
Self {
109
58
value_guard: Cell::new(ptr::null()),
59
+
_marker: PhantomPinned,
110
60
}
111
61
}
112
62
}
···
133
83
Self { value_guard }
134
84
}
135
85
136
-
pub fn register(self, slot: Pin<&'a mut RefGuard<T>>) {
86
+
pub fn register(self, slot: Pin<&'a RefGuard<T>>) {
137
87
// register new ptrs
138
88
let old_value_guard = slot
139
89
.value_guard
140
90
.replace(self.value_guard.get_ref() as *const ValueGuard<T>);
141
91
142
-
let old_ref_guard = self
143
-
.value_guard
144
-
.ref_guard
145
-
.replace(slot.into_ref().get_ref());
92
+
let old_ref_guard = self.value_guard.ref_guard.replace(slot.get_ref());
146
93
147
94
// annul old ptrs
148
95
unsafe { old_value_guard.as_ref() }
···
151
98
.inspect(|guard| guard.value_guard.set(ptr::null()));
152
99
}
153
100
}
101
+
102
+
#[cfg(test)]
103
+
mod test {
104
+
use std::pin;
105
+
106
+
use super::*;
107
+
108
+
fn consume<T>(input: T) {}
109
+
110
+
#[test]
111
+
fn basic() {
112
+
let weak = RefGuard::new();
113
+
let weak_pinned = pin::pin!(weak);
114
+
{
115
+
let mut strong = ValueGuard::new(2);
116
+
let mut strong_pinned = pin::pin!(strong);
117
+
strong_pinned
118
+
.as_ref()
119
+
.registration()
120
+
.register(weak_pinned.as_ref());
121
+
122
+
assert_eq!(strong_pinned.get(), 2);
123
+
assert_eq!(weak_pinned.get(), Some(2));
124
+
125
+
unsafe { strong_pinned.as_mut().get_unchecked_mut() }.set(3);
126
+
assert_eq!(strong_pinned.get(), 3);
127
+
assert_eq!(weak_pinned.get(), Some(3));
128
+
}
129
+
130
+
assert_eq!(weak_pinned.get(), None);
131
+
}
132
+
}