@@ -14,6 +14,10 @@ pub(crate) enum Element<T> {
14
14
/// epoch.
15
15
Occupied ( T , Epoch ) ,
16
16
17
+ /// Like `Occupied`, but the resource has been marked as destroyed
18
+ /// and hasn't been dropped yet.
19
+ Destroyed ( T , Epoch ) ,
20
+
17
21
/// Like `Occupied`, but an error occurred when creating the
18
22
/// resource.
19
23
///
@@ -68,9 +72,11 @@ impl<T, I: id::TypedId> Storage<T, I> {
68
72
let ( index, epoch, _) = id. unzip ( ) ;
69
73
match self . map . get ( index as usize ) {
70
74
Some ( & Element :: Vacant ) => false ,
71
- Some ( & Element :: Occupied ( _, storage_epoch) | & Element :: Error ( storage_epoch, _) ) => {
72
- storage_epoch == epoch
73
- }
75
+ Some (
76
+ & Element :: Occupied ( _, storage_epoch)
77
+ | & Element :: Destroyed ( _, storage_epoch)
78
+ | & Element :: Error ( storage_epoch, _) ,
79
+ ) => storage_epoch == epoch,
74
80
None => false ,
75
81
}
76
82
}
@@ -87,7 +93,9 @@ impl<T, I: id::TypedId> Storage<T, I> {
87
93
let ( result, storage_epoch) = match self . map . get ( index as usize ) {
88
94
Some ( & Element :: Occupied ( ref v, epoch) ) => ( Ok ( Some ( v) ) , epoch) ,
89
95
Some ( & Element :: Vacant ) => return Ok ( None ) ,
90
- Some ( & Element :: Error ( epoch, ..) ) => ( Err ( InvalidId ) , epoch) ,
96
+ Some ( & Element :: Error ( epoch, ..) ) | Some ( & Element :: Destroyed ( .., epoch) ) => {
97
+ ( Err ( InvalidId ) , epoch)
98
+ }
91
99
None => return Err ( InvalidId ) ,
92
100
} ;
93
101
assert_eq ! (
@@ -106,6 +114,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
106
114
Some ( & Element :: Occupied ( ref v, epoch) ) => ( Ok ( v) , epoch) ,
107
115
Some ( & Element :: Vacant ) => panic ! ( "{}[{}] does not exist" , self . kind, index) ,
108
116
Some ( & Element :: Error ( epoch, ..) ) => ( Err ( InvalidId ) , epoch) ,
117
+ Some ( & Element :: Destroyed ( .., epoch) ) => ( Err ( InvalidId ) , epoch) ,
109
118
None => return Err ( InvalidId ) ,
110
119
} ;
111
120
assert_eq ! (
@@ -124,6 +133,29 @@ impl<T, I: id::TypedId> Storage<T, I> {
124
133
Some ( & mut Element :: Occupied ( ref mut v, epoch) ) => ( Ok ( v) , epoch) ,
125
134
Some ( & mut Element :: Vacant ) | None => panic ! ( "{}[{}] does not exist" , self . kind, index) ,
126
135
Some ( & mut Element :: Error ( epoch, ..) ) => ( Err ( InvalidId ) , epoch) ,
136
+ Some ( & mut Element :: Destroyed ( .., epoch) ) => ( Err ( InvalidId ) , epoch) ,
137
+ } ;
138
+ assert_eq ! (
139
+ epoch, storage_epoch,
140
+ "{}[{}] is no longer alive" ,
141
+ self . kind, index
142
+ ) ;
143
+ result
144
+ }
145
+
146
+ /// Like `get_mut`, but returns the element even if it is destroyed.
147
+ ///
148
+ /// In practice, most API entry points should use `get`/`get_mut` so that a
149
+ /// destroyed resource leads to a validation error. This should be used internally
150
+ /// in places where we want to do some manipulation potentially after the element
151
+ /// was destroyed (for example the drop implementation).
152
+ pub ( crate ) fn get_occupied_or_destroyed ( & mut self , id : I ) -> Result < & mut T , InvalidId > {
153
+ let ( index, epoch, _) = id. unzip ( ) ;
154
+ let ( result, storage_epoch) = match self . map . get_mut ( index as usize ) {
155
+ Some ( & mut Element :: Occupied ( ref mut v, epoch) )
156
+ | Some ( & mut Element :: Destroyed ( ref mut v, epoch) ) => ( Ok ( v) , epoch) ,
157
+ Some ( & mut Element :: Vacant ) | None => panic ! ( "{}[{}] does not exist" , self . kind, index) ,
158
+ Some ( & mut Element :: Error ( epoch, ..) ) => ( Err ( InvalidId ) , epoch) ,
127
159
} ;
128
160
assert_eq ! (
129
161
epoch, storage_epoch,
@@ -137,7 +169,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
137
169
match self . map [ id as usize ] {
138
170
Element :: Occupied ( ref v, _) => v,
139
171
Element :: Vacant => panic ! ( "{}[{}] does not exist" , self . kind, id) ,
140
- Element :: Error ( _, _) => panic ! ( "" ) ,
172
+ Element :: Error ( _, _) | Element :: Destroyed ( .. ) => panic ! ( "" ) ,
141
173
}
142
174
}
143
175
@@ -169,13 +201,13 @@ impl<T, I: id::TypedId> Storage<T, I> {
169
201
self . insert_impl ( index as usize , Element :: Error ( epoch, label. to_string ( ) ) )
170
202
}
171
203
172
- pub ( crate ) fn take_and_mark_destroyed ( & mut self , id : I ) -> Result < T , InvalidId > {
204
+ pub ( crate ) fn replace_with_error ( & mut self , id : I ) -> Result < T , InvalidId > {
173
205
let ( index, epoch, _) = id. unzip ( ) ;
174
206
match std:: mem:: replace (
175
207
& mut self . map [ index as usize ] ,
176
208
Element :: Error ( epoch, String :: new ( ) ) ,
177
209
) {
178
- Element :: Vacant => panic ! ( "Cannot mark a vacant resource destroyed " ) ,
210
+ Element :: Vacant => panic ! ( "Cannot access vacant resource" ) ,
179
211
Element :: Occupied ( value, storage_epoch) => {
180
212
assert_eq ! ( epoch, storage_epoch) ;
181
213
Ok ( value)
@@ -184,6 +216,27 @@ impl<T, I: id::TypedId> Storage<T, I> {
184
216
}
185
217
}
186
218
219
+ pub ( crate ) fn get_and_mark_destroyed ( & mut self , id : I ) -> Result < & mut T , InvalidId > {
220
+ let ( index, epoch, _) = id. unzip ( ) ;
221
+ let slot = & mut self . map [ index as usize ] ;
222
+ // borrowck dance: we have to move the element out before we can replace it
223
+ // with another variant with the same value.
224
+ if let & mut Element :: Occupied ( ..) = slot {
225
+ if let Element :: Occupied ( value, storage_epoch) =
226
+ std:: mem:: replace ( slot, Element :: Vacant )
227
+ {
228
+ debug_assert_eq ! ( storage_epoch, epoch) ;
229
+ * slot = Element :: Destroyed ( value, storage_epoch) ;
230
+ }
231
+ }
232
+
233
+ if let Element :: Destroyed ( ref mut value, ..) = * slot {
234
+ Ok ( value)
235
+ } else {
236
+ Err ( InvalidId )
237
+ }
238
+ }
239
+
187
240
pub ( crate ) fn force_replace ( & mut self , id : I , value : T ) {
188
241
let ( index, epoch, _) = id. unzip ( ) ;
189
242
self . map [ index as usize ] = Element :: Occupied ( value, epoch) ;
@@ -192,7 +245,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
192
245
pub ( crate ) fn remove ( & mut self , id : I ) -> Option < T > {
193
246
let ( index, epoch, _) = id. unzip ( ) ;
194
247
match std:: mem:: replace ( & mut self . map [ index as usize ] , Element :: Vacant ) {
195
- Element :: Occupied ( value, storage_epoch) => {
248
+ Element :: Occupied ( value, storage_epoch) | Element :: Destroyed ( value , storage_epoch ) => {
196
249
assert_eq ! ( epoch, storage_epoch) ;
197
250
Some ( value)
198
251
}
@@ -239,7 +292,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
239
292
} ;
240
293
for element in self . map . iter ( ) {
241
294
match * element {
242
- Element :: Occupied ( ..) => report. num_occupied += 1 ,
295
+ Element :: Occupied ( ..) | Element :: Destroyed ( .. ) => report. num_occupied += 1 ,
243
296
Element :: Vacant => report. num_vacant += 1 ,
244
297
Element :: Error ( ..) => report. num_error += 1 ,
245
298
}
0 commit comments