From 17ca8b54fdc0aa2df875fc7b80def4dd56959d7f Mon Sep 17 00:00:00 2001
From: Benoit Germain <benoit.germain@ubisoft.com>
Date: Thu, 23 May 2024 08:35:40 +0200
Subject: on_state_create receives a string argument, "lane" or "keeper"

---
 docs/index.html           | 14 +++++-------
 src/state.cpp             | 56 ++++++++++++++++++++++++++---------------------
 tests/manual_register.lua |  6 ++---
 tests/package.lua         |  8 +++----
 4 files changed, 43 insertions(+), 41 deletions(-)

diff --git a/docs/index.html b/docs/index.html
index d0b06ae..47dc47c 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -400,20 +400,16 @@
 				function/<tt>nil</tt>
 			</td>
 			<td>
-				If provided, will be called in every created Lua state right after initializing the base libraries.
-				<br />
-				Keeper states will call it as well, but only if it is a C function (keeper states are not able to execute any user Lua code).
-				<br />
+				If provided, will be called in every created Lua state right after initializing the base libraries, with a single string argument, either <tt>"lane"</tt> or <tt>"keeper"</tt>.<br/>
+				If it is a C function, a C closure will be reconstructed in the created state from the C pointer. Lanes will raise an error if the function has upvalues.<br/>
+				Keeper states will call it as well, but only if it is a C function (keeper states are not able to execute any user Lua code).<br/>
 				Typical usage is twofold:
 				<ul>
 					<li>Tweak <tt>package.loaders</tt></li>
 					<li>Load some additional C functions in the global space (of course only a C function will be able to do this).</li>
 				</ul>
-				That way, all changes in the state can be properly taken into account when building the function lookup database. Default is <tt>nil</tt>.
-				<br />
-				If <tt>on_state_create()</tt> is a Lua function, it will be transfered normally before the call.
-				<br />
-				If it is a C function, a C closure will be reconstructed in the created state from the C pointer. Lanes will raise an error if the function has upvalues.
+				That way, all changes in the state can be properly taken into account when building the function lookup database. Default is <tt>nil</tt>.<br/>
+				If <tt>on_state_create()</tt> is a Lua function, it will be transfered normally before the call.<br/>
 			</td>
 		</tr>
 
diff --git a/src/state.cpp b/src/state.cpp
index 0175449..83b9e85 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -207,22 +207,24 @@ static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_)
 
 // #################################################################################################
 
+static constexpr char const* kOnStateCreate{ "on_state_create" };
+
 void InitializeOnStateCreate(Universe* U_, lua_State* L_)
 {
     STACK_CHECK_START_REL(L_, 1);                                                                  // L_: settings
-    if (luaG_getfield(L_, -1, "on_state_create") != LuaType::NIL) {                                // L_: settings on_state_create|nil
+    if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) {                                   // L_: settings on_state_create|nil
         // store C function pointer in an internal variable
         U_->onStateCreateFunc = lua_tocfunction(L_, -1);                                           // L_: settings on_state_create
         if (U_->onStateCreateFunc != nullptr) {
             // make sure the function doesn't have upvalues
             char const* _upname{ lua_getupvalue(L_, -1, 1) };                                      // L_: settings on_state_create upval?
             if (_upname != nullptr) { // should be "" for C functions with upvalues if any
-                raise_luaL_error(L_, "on_state_create shouldn't have upvalues");
+                raise_luaL_error(L_, "%s shouldn't have upvalues", kOnStateCreate);
             }
             // remove this C function from the config table so that it doesn't cause problems
             // when we transfer the config table in newly created Lua states
             lua_pushnil(L_);                                                                       // L_: settings on_state_create nil
-            lua_setfield(L_, -3, "on_state_create");                                               // L_: settings on_state_create
+            lua_setfield(L_, -3, kOnStateCreate);                                                  // L_: settings on_state_create
         } else {
             // optim: store marker saying we have such a function in the config table
             U_->onStateCreateFunc = reinterpret_cast<lua_CFunction>(InitializeOnStateCreate);
@@ -265,31 +267,35 @@ lua_State* create_state([[maybe_unused]] Universe* U_, lua_State* from_)
 
 void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_)
 {
-    if (U_->onStateCreateFunc != nullptr) {
-        STACK_CHECK_START_REL(L_, 0);
-        DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl);
-        if (U_->onStateCreateFunc != reinterpret_cast<lua_CFunction>(InitializeOnStateCreate)) {
-            // C function: recreate a closure in the new state, bypassing the lookup scheme
-            lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create()
-        } else { // Lua function located in the config table, copied when we opened "lanes.core"
-            if (mode_ != LookupMode::LaneBody) {
-                // if attempting to call in a keeper state, do nothing because the function doesn't exist there
-                // this doesn't count as an error though
-                STACK_CHECK(L_, 0);
-                return;
-            }
-            kConfigRegKey.pushValue(L_);                                                           // L_: {}
-            STACK_CHECK(L_, 1);
-            std::ignore = luaG_getfield(L_, -1, "on_state_create");                                // L_: {} on_state_create()
-            lua_remove(L_, -2);                                                                    // L_: on_state_create()
+    if (U_->onStateCreateFunc == nullptr) {
+        return;
+    }
+
+    STACK_CHECK_START_REL(L_, 0);
+    DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl);
+    if (U_->onStateCreateFunc != reinterpret_cast<lua_CFunction>(InitializeOnStateCreate)) {
+        // C function: recreate a closure in the new state, bypassing the lookup scheme
+        lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create()
+    } else { // Lua function located in the config table, copied when we opened "lanes.core"
+        if (mode_ != LookupMode::LaneBody) {
+            // if attempting to call in a keeper state, do nothing because the function doesn't exist there
+            // this doesn't count as an error though
+            STACK_CHECK(L_, 0);
+            return;
         }
+        kConfigRegKey.pushValue(L_);                                                               // L_: {}
         STACK_CHECK(L_, 1);
-        // capture error and raise it in caller state
-        if (lua_pcall(L_, 0, 0, 0) != LUA_OK) {
-            raise_luaL_error(from_, "on_state_create failed: \"%s\"", lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1)));
-        }
-        STACK_CHECK(L_, 0);
+        std::ignore = luaG_getfield(L_, -1, kOnStateCreate);                                       // L_: {} on_state_create()
+        lua_remove(L_, -2);                                                                        // L_: on_state_create()
     }
+    STACK_CHECK(L_, 1);
+    // capture error and raise it in caller state
+    std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" };
+    std::ignore = lua_pushstringview(L_, _stateType);                                              // L_: on_state_create() "<type>"
+    if (lua_pcall(L_, 1, 0, 0) != LUA_OK) {
+        raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate, lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1)));
+    }
+    STACK_CHECK(L_, 0);
 }
 
 // #################################################################################################
diff --git a/tests/manual_register.lua b/tests/manual_register.lua
index 23b33c1..a8f2098 100644
--- a/tests/manual_register.lua
+++ b/tests/manual_register.lua
@@ -1,7 +1,7 @@
 
 local register_func = true
 
-local RequireAModuleThatExportsGlobalFunctions = function()
+local RequireAModuleThatExportsGlobalFunctions = function(type_)
 	-- grab some module that exports C functions, this is good enough for our purpose
 	local lfs = require "lfs"
 	-- make one of these a global
@@ -11,14 +11,14 @@ local RequireAModuleThatExportsGlobalFunctions = function()
 	if register_func then
 		lanes.register( "GlobalFunc", GlobalFunc)
 	end
-	print("RequireAModuleThatExportsGlobalFunctions done:", lanes.nameof(GlobalFunc))
+	print(type_, "RequireAModuleThatExportsGlobalFunctions done:", lanes.nameof(GlobalFunc))
 end
 
 
 local lanes = require "lanes".configure{ with_timers = false, on_state_create = RequireAModuleThatExportsGlobalFunctions}
 
 -- load some module that adds C functions to the global space
-RequireAModuleThatExportsGlobalFunctions()
+RequireAModuleThatExportsGlobalFunctions("main")
 
 local GlobalFuncUpval = GlobalFunc
 
diff --git a/tests/package.lua b/tests/package.lua
index de11c9e..4e8b59f 100644
--- a/tests/package.lua
+++ b/tests/package.lua
@@ -2,21 +2,21 @@ local loaders = package.loaders or package.searchers
 
 assert(nil == loaders[5])
 
-local configure_loaders = function()
+local configure_loaders = function(type_)
 	table.insert(loaders, 4, function() end)
 	assert(loaders[1])
 	assert(loaders[2])
 	assert(loaders[3])
 	assert(loaders[4])
 	assert(loaders[5])
-	print "loaders configured!"
+	print(type_, "loaders configured!")
 end
 
-configure_loaders()
+configure_loaders("main")
 
 for k,v in pairs(loaders) do
 	print( k, type(v))
 end
 
 lanes = require "lanes"
-lanes.configure{with_timers=false, on_state_create = configure_loaders}
\ No newline at end of file
+lanes.configure{on_state_create = configure_loaders}
\ No newline at end of file
-- 
cgit v1.2.3-55-g6feb