@@ -2,7 +2,7 @@ use std::any::TypeId;
22use std:: cell:: { BorrowError , BorrowMutError , RefCell } ;
33use std:: marker:: PhantomData ;
44use std:: ops:: Deref ;
5- use std:: os:: raw:: c_int;
5+ use std:: os:: raw:: { c_char , c_int} ;
66use std:: panic:: Location ;
77use std:: result:: Result as StdResult ;
88use std:: { fmt, mem, ptr} ;
@@ -347,40 +347,78 @@ impl Lua {
347347 unsafe { self . lock ( ) . load_std_libs ( libs) }
348348 }
349349
350- /// Loads module `modname` into an existing Lua state using the specified entrypoint
351- /// function.
350+ /// Registers module into an existing Lua state using the specified value.
352351 ///
353- /// Internally calls the Lua function `func` with the string `modname` as an argument,
354- /// sets the call result to `package.loaded[modname]` and returns copy of the result .
352+ /// After registration, the given value will always be immediately returned when the
353+ /// given module is [required] .
355354 ///
356- /// If `package.loaded[modname]` value is not nil, returns copy of the value without
357- /// calling the function.
355+ /// [required]: https://www.lua.org/manual/5.4/manual.html#pdf-require
356+ pub fn register_module ( & self , modname : & str , value : impl IntoLua ) -> Result < ( ) > {
357+ #[ cfg( not( feature = "luau" ) ) ]
358+ const LOADED_MODULES_KEY : * const c_char = ffi:: LUA_LOADED_TABLE ;
359+ #[ cfg( feature = "luau" ) ]
360+ const LOADED_MODULES_KEY : * const c_char = cstr ! ( "_REGISTEREDMODULES" ) ;
361+
362+ if cfg ! ( feature = "luau" ) && !modname. starts_with ( '@' ) {
363+ return Err ( Error :: runtime ( "module name must begin with '@'" ) ) ;
364+ }
365+ unsafe {
366+ self . exec_raw :: < ( ) > ( value, |state| {
367+ ffi:: luaL_getsubtable ( state, ffi:: LUA_REGISTRYINDEX , LOADED_MODULES_KEY ) ;
368+ ffi:: lua_pushlstring ( state, modname. as_ptr ( ) as * const c_char , modname. len ( ) as _ ) ;
369+ ffi:: lua_pushvalue ( state, -3 ) ;
370+ ffi:: lua_rawset ( state, -3 ) ;
371+ } )
372+ }
373+ }
374+
375+ /// Preloads module into an existing Lua state using the specified loader function.
358376 ///
359- /// If the function does not return a non-nil value then this method assigns true to
360- /// `package.loaded[modname]` .
377+ /// When the module is required, the loader function will be called with module name as the
378+ /// first argument .
361379 ///
362- /// Behavior is similar to Lua's [`require `] function .
380+ /// This is similar to setting the [`package.preload[modname] `] field .
363381 ///
364- /// [`require`]: https://www.lua.org/manual/5.4/manual.html#pdf-require
365- pub fn load_from_function < T > ( & self , modname : & str , func : Function ) -> Result < T >
366- where
367- T : FromLua ,
368- {
369- let lua = self . lock ( ) ;
370- let state = lua. state ( ) ;
382+ /// [`package.preload[modname]`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.preload
383+ #[ cfg( not( feature = "luau" ) ) ]
384+ #[ cfg_attr( docsrs, doc( cfg( not( feature = "luau" ) ) ) ) ]
385+ pub fn preload_module ( & self , modname : & str , func : Function ) -> Result < ( ) > {
386+ #[ cfg( any( feature = "lua54" , feature = "lua53" , feature = "lua52" ) ) ]
387+ let preload = unsafe {
388+ self . exec_raw :: < Option < Table > > ( ( ) , |state| {
389+ ffi:: lua_getfield ( state, ffi:: LUA_REGISTRYINDEX , ffi:: LUA_PRELOAD_TABLE ) ;
390+ } ) ?
391+ } ;
392+ #[ cfg( any( feature = "lua51" , feature = "luajit" ) ) ]
393+ let preload = unsafe {
394+ self . exec_raw :: < Option < Table > > ( ( ) , |state| {
395+ if ffi:: lua_getfield ( state, ffi:: LUA_REGISTRYINDEX , ffi:: LUA_LOADED_TABLE ) != ffi:: LUA_TNIL {
396+ ffi:: luaL_getsubtable ( state, -1 , ffi:: LUA_LOADLIBNAME ) ;
397+ ffi:: luaL_getsubtable ( state, -1 , cstr ! ( "preload" ) ) ;
398+ ffi:: lua_rotate ( state, 1 , 1 ) ;
399+ }
400+ } ) ?
401+ } ;
402+ if let Some ( preload) = preload {
403+ preload. raw_set ( modname, func) ?;
404+ }
405+ Ok ( ( ) )
406+ }
407+
408+ #[ doc( hidden) ]
409+ #[ deprecated( since = "0.11.0" , note = "Use `register_module` instead" ) ]
410+ #[ cfg( not( feature = "luau" ) ) ]
411+ #[ cfg( not( tarpaulin_include) ) ]
412+ pub fn load_from_function < T : FromLua > ( & self , modname : & str , func : Function ) -> Result < T > {
371413 let loaded = unsafe {
372- let _sg = StackGuard :: new ( state) ;
373- check_stack ( state, 2 ) ?;
374- protect_lua ! ( state, 0 , 1 , fn ( state) {
375- ffi:: luaL_getsubtable( state, ffi:: LUA_REGISTRYINDEX , cstr!( "_LOADED" ) ) ;
376- } ) ?;
377- Table ( lua. pop_ref ( ) )
414+ self . exec_raw :: < Table > ( ( ) , |state| {
415+ ffi:: luaL_getsubtable ( state, ffi:: LUA_REGISTRYINDEX , ffi:: LUA_LOADED_TABLE ) ;
416+ } ) ?
378417 } ;
379418
380- let modname = unsafe { lua. create_string ( modname) ? } ;
381- let value = match loaded. raw_get ( & modname) ? {
419+ let value = match loaded. raw_get ( modname) ? {
382420 Value :: Nil => {
383- let result = match func. call ( & modname) ? {
421+ let result = match func. call ( modname) ? {
384422 Value :: Nil => Value :: Boolean ( true ) ,
385423 res => res,
386424 } ;
@@ -394,24 +432,14 @@ impl Lua {
394432
395433 /// Unloads module `modname`.
396434 ///
397- /// Removes module from the [`package.loaded`] table which allows to load it again.
398- /// It does not support unloading binary Lua modules since they are internally cached and can be
399- /// unloaded only by closing Lua state.
435+ /// This method does not support unloading binary Lua modules since they are internally cached
436+ /// and can be unloaded only by closing Lua state.
437+ ///
438+ /// This is similar to calling [`Lua::register_module`] with `Nil` value.
400439 ///
401440 /// [`package.loaded`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.loaded
402- pub fn unload ( & self , modname : & str ) -> Result < ( ) > {
403- let lua = self . lock ( ) ;
404- let state = lua. state ( ) ;
405- let loaded = unsafe {
406- let _sg = StackGuard :: new ( state) ;
407- check_stack ( state, 2 ) ?;
408- protect_lua ! ( state, 0 , 1 , fn ( state) {
409- ffi:: luaL_getsubtable( state, ffi:: LUA_REGISTRYINDEX , cstr!( "_LOADED" ) ) ;
410- } ) ?;
411- Table ( lua. pop_ref ( ) )
412- } ;
413-
414- loaded. raw_set ( modname, Nil )
441+ pub fn unload_module ( & self , modname : & str ) -> Result < ( ) > {
442+ self . register_module ( modname, Nil )
415443 }
416444
417445 // Executes module entrypoint function, which returns only one Value.
0 commit comments