1
1
use std:: ffi:: CStr ;
2
+ use std:: mem;
2
3
use std:: os:: raw:: c_int;
3
4
4
5
use crate :: error:: Result ;
@@ -12,18 +13,27 @@ pub use require::{NavigateError, Require};
12
13
impl Lua {
13
14
/// Create a custom Luau `require` function using provided [`Require`] implementation to find
14
15
/// and load modules.
15
- ///
16
- /// The provided object is stored in the Lua registry and will not be garbage collected
17
- /// until the Lua state is closed.
18
16
#[ cfg( any( feature = "luau" , doc) ) ]
19
17
#[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
20
18
pub fn create_require_function < R : Require + ' static > ( & self , require : R ) -> Result < Function > {
19
+ unsafe extern "C-unwind" fn mlua_require ( state : * mut ffi:: lua_State ) -> c_int {
20
+ let mut ar: ffi:: lua_Debug = mem:: zeroed ( ) ;
21
+ if ffi:: lua_getinfo ( state, 1 , cstr ! ( "s" ) , & mut ar) == 0 {
22
+ ffi:: luaL_error ( state, cstr ! ( "require is not supported in this context" ) ) ;
23
+ }
24
+ let top = ffi:: lua_gettop ( state) ;
25
+ ffi:: lua_pushvalue ( state, ffi:: lua_upvalueindex ( 2 ) ) ; // the "proxy" require function
26
+ ffi:: lua_pushvalue ( state, 1 ) ; // require path
27
+ ffi:: lua_pushstring ( state, ar. source ) ; // current file
28
+ ffi:: lua_call ( state, 2 , ffi:: LUA_MULTRET ) ;
29
+ ffi:: lua_gettop ( state) - top
30
+ }
31
+
21
32
unsafe {
22
33
self . exec_raw ( ( ) , move |state| {
23
34
let requirer_ptr = ffi:: lua_newuserdata_t :: < Box < dyn Require > > ( state, Box :: new ( require) ) ;
24
- // Keep the require object in the registry to prevent it from being garbage collected
25
- ffi:: lua_rawsetp ( state, ffi:: LUA_REGISTRYINDEX , requirer_ptr as * const _ ) ;
26
- ffi:: lua_pushrequire ( state, require:: init_config, requirer_ptr as * mut _ ) ;
35
+ ffi:: luarequire_pushproxyrequire ( state, require:: init_config, requirer_ptr as * mut _ ) ;
36
+ ffi:: lua_pushcclosured ( state, mlua_require, cstr ! ( "require" ) , 2 ) ;
27
37
} )
28
38
}
29
39
}
0 commit comments