11use std:: ffi:: CStr ;
2+ use std:: mem;
23use std:: os:: raw:: c_int;
34
45use crate :: error:: Result ;
@@ -12,18 +13,27 @@ pub use require::{NavigateError, Require};
1213impl Lua {
1314 /// Create a custom Luau `require` function using provided [`Require`] implementation to find
1415 /// 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.
1816 #[ cfg( any( feature = "luau" , doc) ) ]
1917 #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
2018 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+
2132 unsafe {
2233 self . exec_raw ( ( ) , move |state| {
2334 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 ) ;
2737 } )
2838 }
2939 }
0 commit comments