@@ -2,7 +2,7 @@ use std::any::TypeId;
2
2
use std:: cell:: { BorrowError , BorrowMutError , RefCell } ;
3
3
use std:: marker:: PhantomData ;
4
4
use std:: ops:: Deref ;
5
- use std:: os:: raw:: c_int;
5
+ use std:: os:: raw:: { c_char , c_int} ;
6
6
use std:: panic:: Location ;
7
7
use std:: result:: Result as StdResult ;
8
8
use std:: { fmt, mem, ptr} ;
@@ -347,40 +347,78 @@ impl Lua {
347
347
unsafe { self . lock ( ) . load_std_libs ( libs) }
348
348
}
349
349
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.
352
351
///
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] .
355
354
///
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.
358
376
///
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 .
361
379
///
362
- /// Behavior is similar to Lua's [`require `] function .
380
+ /// This is similar to setting the [`package.preload[modname] `] field .
363
381
///
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 > {
371
413
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
+ } ) ?
378
417
} ;
379
418
380
- let modname = unsafe { lua. create_string ( modname) ? } ;
381
- let value = match loaded. raw_get ( & modname) ? {
419
+ let value = match loaded. raw_get ( modname) ? {
382
420
Value :: Nil => {
383
- let result = match func. call ( & modname) ? {
421
+ let result = match func. call ( modname) ? {
384
422
Value :: Nil => Value :: Boolean ( true ) ,
385
423
res => res,
386
424
} ;
@@ -394,24 +432,14 @@ impl Lua {
394
432
395
433
/// Unloads module `modname`.
396
434
///
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.
400
439
///
401
440
/// [`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 )
415
443
}
416
444
417
445
// Executes module entrypoint function, which returns only one Value.
0 commit comments