1
- use std:: cell:: Cell ;
2
1
use std:: marker:: PhantomData ;
3
2
use std:: mem:: MaybeUninit ;
4
3
use std:: ops:: Deref ;
5
4
5
+ // NOTE: These types _cannot_ be public, as doing so may cause external implementations to
6
+ // implement different behavior for them, which would make transmutes between
7
+ // SomeWrapper<Aliased<T, NoDrop>> and SomeWrapper<Aliased<T, DoDrop>> unsound.
8
+ pub ( crate ) struct NoDrop ;
9
+ pub ( crate ) struct DoDrop ;
10
+
11
+ pub trait DropBehavior {
12
+ fn do_drop ( ) -> bool ;
13
+ }
14
+ impl DropBehavior for NoDrop {
15
+ fn do_drop ( ) -> bool {
16
+ false
17
+ }
18
+ }
19
+ impl DropBehavior for DoDrop {
20
+ fn do_drop ( ) -> bool {
21
+ true
22
+ }
23
+ }
24
+
6
25
/// A `T` that is aliased across the two map copies.
7
26
///
8
27
/// You should be able to mostly ignore this type, as it can generally be treated exactly like a
@@ -13,14 +32,19 @@ use std::ops::Deref;
13
32
/// implementing your trait specifically for `Aliased<T>` where possible, or by manually
14
33
/// dereferencing to get the `&T` before using the trait.
15
34
#[ repr( transparent) ]
16
- pub struct Aliased < T > {
35
+ pub struct Aliased < T , U >
36
+ where
37
+ U : DropBehavior ,
38
+ {
17
39
aliased : MaybeUninit < T > ,
18
40
41
+ drop_behavior : PhantomData < U > ,
42
+
19
43
// We cannot implement Send just because T is Send since we're aliasing it.
20
44
_no_auto_send : PhantomData < * const T > ,
21
45
}
22
46
23
- impl < T > Aliased < T > {
47
+ impl < T > Aliased < T , NoDrop > {
24
48
/// Create an alias of the inner `T`.
25
49
///
26
50
/// # Safety
@@ -36,6 +60,7 @@ impl<T> Aliased<T> {
36
60
// b) we only expose _either_ &T while aliased, or &mut after the aliasing ends.
37
61
Aliased {
38
62
aliased : unsafe { std:: ptr:: read ( & self . aliased ) } ,
63
+ drop_behavior : PhantomData ,
39
64
_no_auto_send : PhantomData ,
40
65
}
41
66
}
@@ -48,6 +73,21 @@ impl<T> Aliased<T> {
48
73
pub ( crate ) fn from ( t : T ) -> Self {
49
74
Self {
50
75
aliased : MaybeUninit :: new ( t) ,
76
+ drop_behavior : PhantomData ,
77
+ _no_auto_send : PhantomData ,
78
+ }
79
+ }
80
+
81
+ /// Turn this aliased `T` into one that will drop the `T` when it is dropped.
82
+ ///
83
+ /// # Safety
84
+ ///
85
+ /// This is safe if and only if `self` is the last alias for the `T`.
86
+ pub ( crate ) unsafe fn dropping ( self ) -> Aliased < T , DoDrop > {
87
+ Aliased {
88
+ // safety:
89
+ aliased : std:: ptr:: read ( & self . aliased ) ,
90
+ drop_behavior : PhantomData ,
51
91
_no_auto_send : PhantomData ,
52
92
}
53
93
}
@@ -58,72 +98,63 @@ impl<T> Aliased<T> {
58
98
// This implies that we are only Send if T is Send+Sync, and Sync if T is Sync.
59
99
//
60
100
// Note that these bounds are stricter than what the compiler would auto-generate for the type.
61
- unsafe impl < T > Send for Aliased < T > where T : Send + Sync { }
62
- unsafe impl < T > Sync for Aliased < T > where T : Sync { }
63
-
64
- // XXX: Is this a problem if people start nesting evmaps?
65
- // I feel like the answer is yes.
66
- thread_local ! {
67
- static DROP_FOR_REAL : Cell <bool > = Cell :: new( false ) ;
101
+ unsafe impl < T , U > Send for Aliased < T , U >
102
+ where
103
+ U : DropBehavior ,
104
+ T : Send + Sync ,
105
+ {
68
106
}
69
-
70
- /// Make _any_ dropped `Aliased` actually drop their inner `T`.
71
- ///
72
- /// Be very careful: this function will cause _all_ dropped `Aliased` to drop their `T`.
73
- ///
74
- /// When the return value is dropped, dropping `Aliased` will have no effect again.
75
- ///
76
- /// # Safety
77
- ///
78
- /// Only set this when any following `Aliased` that are dropped are no longer aliased.
79
- pub ( crate ) unsafe fn drop_copies ( ) -> impl Drop {
80
- struct DropGuard ;
81
- impl Drop for DropGuard {
82
- fn drop ( & mut self ) {
83
- DROP_FOR_REAL . with ( |dfr| dfr. set ( false ) ) ;
84
- }
85
- }
86
- let guard = DropGuard ;
87
- DROP_FOR_REAL . with ( |dfr| dfr. set ( true ) ) ;
88
- guard
107
+ unsafe impl < T , U > Sync for Aliased < T , U >
108
+ where
109
+ U : DropBehavior ,
110
+ T : Sync ,
111
+ {
89
112
}
90
113
91
- impl < T > Drop for Aliased < T > {
114
+ impl < T , U > Drop for Aliased < T , U >
115
+ where
116
+ U : DropBehavior ,
117
+ {
92
118
fn drop ( & mut self ) {
93
- DROP_FOR_REAL . with ( move |drop_for_real| {
94
- if drop_for_real. get ( ) {
95
- // safety:
96
- // MaybeUninit<T> was created from a valid T.
97
- // That T has not been dropped (drop_copies is unsafe).
98
- // T is no longer aliased (drop_copies is unsafe),
99
- // so we are allowed to re-take ownership of the T.
100
- unsafe { std:: ptr:: drop_in_place ( self . aliased . as_mut_ptr ( ) ) }
101
- }
102
- } )
119
+ if U :: do_drop ( ) {
120
+ // safety:
121
+ // MaybeUninit<T> was created from a valid T.
122
+ // That T has not been dropped (getting a Aliased<T, DoDrop> is unsafe).
123
+ // T is no longer aliased (by the safety assumption of getting a Aliased<T, DoDrop>),
124
+ // so we are allowed to re-take ownership of the T.
125
+ unsafe { std:: ptr:: drop_in_place ( self . aliased . as_mut_ptr ( ) ) }
126
+ }
103
127
}
104
128
}
105
129
106
- impl < T > AsRef < T > for Aliased < T > {
130
+ impl < T , U > AsRef < T > for Aliased < T , U >
131
+ where
132
+ U : DropBehavior ,
133
+ {
107
134
fn as_ref ( & self ) -> & T {
108
135
// safety:
109
136
// MaybeUninit<T> was created from a valid T.
110
- // That T has not been dropped (drop_copies is unsafe).
137
+ // That T has not been dropped (getting a Aliased<T, DoDrop> is unsafe).
111
138
// All we have done to T is alias it. But, since we only give out &T
112
139
// (which should be legal anyway), we're fine.
113
140
unsafe { & * self . aliased . as_ptr ( ) }
114
141
}
115
142
}
116
143
117
- impl < T > Deref for Aliased < T > {
144
+ impl < T , U > Deref for Aliased < T , U >
145
+ where
146
+ U : DropBehavior ,
147
+ {
118
148
type Target = T ;
119
149
fn deref ( & self ) -> & Self :: Target {
120
150
self . as_ref ( )
121
151
}
122
152
}
123
153
124
154
use std:: hash:: { Hash , Hasher } ;
125
- impl < T > Hash for Aliased < T >
155
+ impl < T , U > Hash for Aliased < T , U >
126
156
where
157
+ U : DropBehavior ,
127
158
T : Hash ,
128
159
{
129
160
fn hash < H > ( & self , state : & mut H )
@@ -135,17 +166,19 @@ where
135
166
}
136
167
137
168
use std:: fmt;
138
- impl < T > fmt:: Debug for Aliased < T >
169
+ impl < T , U > fmt:: Debug for Aliased < T , U >
139
170
where
171
+ U : DropBehavior ,
140
172
T : fmt:: Debug ,
141
173
{
142
174
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
143
175
self . as_ref ( ) . fmt ( f)
144
176
}
145
177
}
146
178
147
- impl < T > PartialEq for Aliased < T >
179
+ impl < T , U > PartialEq for Aliased < T , U >
148
180
where
181
+ U : DropBehavior ,
149
182
T : PartialEq ,
150
183
{
151
184
fn eq ( & self , other : & Self ) -> bool {
@@ -157,10 +190,16 @@ where
157
190
}
158
191
}
159
192
160
- impl < T > Eq for Aliased < T > where T : Eq { }
193
+ impl < T , U > Eq for Aliased < T , U >
194
+ where
195
+ U : DropBehavior ,
196
+ T : Eq ,
197
+ {
198
+ }
161
199
162
- impl < T > PartialOrd for Aliased < T >
200
+ impl < T , U > PartialOrd for Aliased < T , U >
163
201
where
202
+ U : DropBehavior ,
164
203
T : PartialOrd ,
165
204
{
166
205
fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
@@ -184,8 +223,9 @@ where
184
223
}
185
224
}
186
225
187
- impl < T > Ord for Aliased < T >
226
+ impl < T , U > Ord for Aliased < T , U >
188
227
where
228
+ U : DropBehavior ,
189
229
T : Ord ,
190
230
{
191
231
fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
@@ -194,7 +234,10 @@ where
194
234
}
195
235
196
236
use std:: borrow:: Borrow ;
197
- impl < T > Borrow < T > for Aliased < T > {
237
+ impl < T , U > Borrow < T > for Aliased < T , U >
238
+ where
239
+ U : DropBehavior ,
240
+ {
198
241
fn borrow ( & self ) -> & T {
199
242
self . as_ref ( )
200
243
}
@@ -213,40 +256,52 @@ impl<T> Borrow<T> for Aliased<T> {
213
256
// But unfortunately that won't work due to trait coherence.
214
257
// Instead, we manually write the nice Borrow impls from std.
215
258
// This won't help with custom Borrow impls, but gets you pretty far.
216
- impl Borrow < str > for Aliased < String > {
259
+ impl < U > Borrow < str > for Aliased < String , U >
260
+ where
261
+ U : DropBehavior ,
262
+ {
217
263
fn borrow ( & self ) -> & str {
218
264
self . as_ref ( )
219
265
}
220
266
}
221
- impl Borrow < std:: path:: Path > for Aliased < std:: path:: PathBuf > {
267
+ impl < U > Borrow < std:: path:: Path > for Aliased < std:: path:: PathBuf , U >
268
+ where
269
+ U : DropBehavior ,
270
+ {
222
271
fn borrow ( & self ) -> & std:: path:: Path {
223
272
self . as_ref ( )
224
273
}
225
274
}
226
- impl < T > Borrow < [ T ] > for Aliased < Vec < T > > {
275
+ impl < T , U > Borrow < [ T ] > for Aliased < Vec < T > , U >
276
+ where
277
+ U : DropBehavior ,
278
+ {
227
279
fn borrow ( & self ) -> & [ T ] {
228
280
self . as_ref ( )
229
281
}
230
282
}
231
- impl < T > Borrow < T > for Aliased < Box < T > >
283
+ impl < T , U > Borrow < T > for Aliased < Box < T > , U >
232
284
where
233
285
T : ?Sized ,
286
+ U : DropBehavior ,
234
287
{
235
288
fn borrow ( & self ) -> & T {
236
289
self . as_ref ( )
237
290
}
238
291
}
239
- impl < T > Borrow < T > for Aliased < std:: sync:: Arc < T > >
292
+ impl < T , U > Borrow < T > for Aliased < std:: sync:: Arc < T > , U >
240
293
where
241
294
T : ?Sized ,
295
+ U : DropBehavior ,
242
296
{
243
297
fn borrow ( & self ) -> & T {
244
298
self . as_ref ( )
245
299
}
246
300
}
247
- impl < T > Borrow < T > for Aliased < std:: rc:: Rc < T > >
301
+ impl < T , U > Borrow < T > for Aliased < std:: rc:: Rc < T > , U >
248
302
where
249
303
T : ?Sized ,
304
+ U : DropBehavior ,
250
305
{
251
306
fn borrow ( & self ) -> & T {
252
307
self . as_ref ( )
0 commit comments