@@ -19,7 +19,9 @@ use crate::util::{
19
19
/// See [`Lua::scope`] for more details.
20
20
pub struct Scope < ' scope , ' env : ' scope > {
21
21
lua : LuaGuard ,
22
+ // Internal destructors run first, then user destructors (based on the declaration order)
22
23
destructors : Destructors < ' env > ,
24
+ user_destructors : UserDestructors < ' env > ,
23
25
_scope_invariant : PhantomData < & ' scope mut & ' scope ( ) > ,
24
26
_env_invariant : PhantomData < & ' env mut & ' env ( ) > ,
25
27
}
@@ -29,11 +31,14 @@ type DestructorCallback<'a> = Box<dyn FnOnce(&RawLua, ValueRef) -> Vec<Box<dyn F
29
31
// Implement Drop on Destructors instead of Scope to avoid compilation error
30
32
struct Destructors < ' a > ( RefCell < Vec < ( ValueRef , DestructorCallback < ' a > ) > > ) ;
31
33
34
+ struct UserDestructors < ' a > ( RefCell < Vec < Box < dyn FnOnce ( ) + ' a > > > ) ;
35
+
32
36
impl < ' scope , ' env : ' scope > Scope < ' scope , ' env > {
33
37
pub ( crate ) fn new ( lua : LuaGuard ) -> Self {
34
38
Scope {
35
39
lua,
36
40
destructors : Destructors ( RefCell :: new ( Vec :: new ( ) ) ) ,
41
+ user_destructors : UserDestructors ( RefCell :: new ( Vec :: new ( ) ) ) ,
37
42
_scope_invariant : PhantomData ,
38
43
_env_invariant : PhantomData ,
39
44
}
@@ -215,6 +220,31 @@ impl<'scope, 'env: 'scope> Scope<'scope, 'env> {
215
220
}
216
221
}
217
222
223
+ /// Adds a destructor function to be run when the scope ends.
224
+ ///
225
+ /// This functionality is useful for cleaning up any resources after the scope ends.
226
+ ///
227
+ /// # Example
228
+ ///
229
+ /// ```rust
230
+ /// # use mlua::{Error, Lua, Result};
231
+ /// # fn main() -> Result<()> {
232
+ /// let lua = Lua::new();
233
+ /// let ud = lua.create_any_userdata(String::from("hello"))?;
234
+ /// lua.scope(|scope| {
235
+ /// scope.add_destructor(|| {
236
+ /// _ = ud.take::<String>();
237
+ /// });
238
+ /// // Run the code that uses `ud` here
239
+ /// Ok(())
240
+ /// })?;
241
+ /// assert!(matches!(ud.borrow::<String>(), Err(Error::UserDataDestructed)));
242
+ /// # Ok(())
243
+ /// # }
244
+ pub fn add_destructor ( & ' scope self , destructor : impl FnOnce ( ) + ' env ) {
245
+ self . user_destructors . 0 . borrow_mut ( ) . push ( Box :: new ( destructor) ) ;
246
+ }
247
+
218
248
unsafe fn create_callback ( & ' scope self , f : ScopedCallback < ' scope > ) -> Result < Function > {
219
249
let f = mem:: transmute :: < ScopedCallback , Callback > ( f) ;
220
250
let f = self . lua . create_callback ( f) ?;
@@ -271,3 +301,12 @@ impl Drop for Destructors<'_> {
271
301
}
272
302
}
273
303
}
304
+
305
+ impl Drop for UserDestructors < ' _ > {
306
+ fn drop ( & mut self ) {
307
+ let destructors = mem:: take ( & mut * self . 0 . borrow_mut ( ) ) ;
308
+ for destructor in destructors {
309
+ destructor ( ) ;
310
+ }
311
+ }
312
+ }
0 commit comments