From 3214c7bd7e77fdd458d64ec101a8a67287b59ffa Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 1 Aug 2024 16:09:11 -0400
Subject: Add lua_push(), lua_to(), lua_[gs]etfieldv(), lua_raw[gs]etfield().

Leverage C++ overloads to allow use of generic function names disambiguated by
argument type.

This allows using templates for certain common operation sequences.
---
 indra/llcommon/lua_function.cpp |  17 ++---
 indra/llcommon/lua_function.h   | 162 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+), 11 deletions(-)

diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index 42bba80ed5..b173d17ede 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -32,6 +32,8 @@
 #include "lualistener.h"
 #include "stringize.h"
 
+using namespace std::literals;      // e.g. std::string_view literals: "this"sv
+
 const S32 INTERRUPTS_MAX_LIMIT = 20000;
 const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
 
@@ -41,7 +43,7 @@ const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
 int DistinctInt::mValues{0};
 
 /*****************************************************************************
-*   luau namespace
+*   lluau namespace
 *****************************************************************************/
 namespace
 {
@@ -93,21 +95,14 @@ fsyspath lluau::source_path(lua_State* L)
 
 void lluau::set_interrupts_counter(lua_State *L, S32 counter)
 {
-    luaL_checkstack(L, 2, nullptr);
-    lua_pushstring(L, "_INTERRUPTS");
-    lua_pushinteger(L, counter);
-    lua_rawset(L, LUA_REGISTRYINDEX);
+    lua_rawsetfield(L, LUA_REGISTRYINDEX, "_INTERRUPTS"sv, lua_Integer(counter));
 }
 
 void lluau::check_interrupts_counter(lua_State* L)
 {
-    luaL_checkstack(L, 1, nullptr);
-    lua_pushstring(L, "_INTERRUPTS");
-    lua_rawget(L, LUA_REGISTRYINDEX);
-    S32 counter = lua_tointeger(L, -1);
-    lua_pop(L, 1);
+    auto counter = lua_rawgetfield<lua_Integer>(L, LUA_REGISTRYINDEX, "_INTERRUPTS"sv);
 
-    lluau::set_interrupts_counter(L, ++counter);
+    set_interrupts_counter(L, ++counter);
     if (counter > INTERRUPTS_MAX_LIMIT) 
     {
         lluau::error(L, "Possible infinite loop, terminated.");
diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h
index 7f7a7566f3..7b59af30f5 100644
--- a/indra/llcommon/lua_function.h
+++ b/indra/llcommon/lua_function.h
@@ -18,6 +18,7 @@
 #include "luau/lualib.h"
 #include "fsyspath.h"
 #include "llerror.h"
+#include "llsd.h"
 #include "stringize.h"
 #include <exception>                // std::uncaught_exceptions()
 #include <memory>                   // std::shared_ptr
@@ -168,6 +169,167 @@ private:
     int mIndex;
 };
 
+/*****************************************************************************
+*   lua_push() wrappers for generic code
+*****************************************************************************/
+inline
+void lua_push(lua_State* L, bool b)
+{
+    lua_pushboolean(L, int(b));
+}
+
+inline
+void lua_push(lua_State* L, lua_CFunction fn)
+{
+    lua_pushcfunction(L, fn, "");
+}
+
+inline
+void lua_push(lua_State* L, lua_Integer n)
+{
+    lua_pushinteger(L, n);
+}
+
+inline
+void lua_push(lua_State* L, void* p)
+{
+    lua_pushlightuserdata(L, p);
+}
+
+inline
+void lua_push(lua_State* L, const LLSD& data)
+{
+    lua_pushllsd(L, data);
+}
+
+inline
+void lua_push(lua_State* L, const char* s, size_t len)
+{
+    lua_pushlstring(L, s, len);
+}
+
+inline
+void lua_push(lua_State* L)
+{
+    lua_pushnil(L);
+}
+
+inline
+void lua_push(lua_State* L, lua_Number n)
+{
+    lua_pushnumber(L, n);
+}
+
+inline
+void lua_push(lua_State* L, const std::string& s)
+{
+    lua_pushstdstring(L, s);
+}
+
+inline
+void lua_push(lua_State* L, const char* s)
+{
+    lua_pushstring(L, s);
+}
+
+/*****************************************************************************
+*   lua_to() wrappers for generic code
+*****************************************************************************/
+template <typename T>
+auto lua_to(lua_State* L, int index);
+
+template <>
+inline
+auto lua_to<bool>(lua_State* L, int index)
+{
+    return lua_toboolean(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_CFunction>(lua_State* L, int index)
+{
+    return lua_tocfunction(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_Integer>(lua_State* L, int index)
+{
+    return lua_tointeger(L, index);
+}
+
+template <>
+inline
+auto lua_to<LLSD>(lua_State* L, int index)
+{
+    return lua_tollsd(L, index);
+}
+
+template <>
+inline
+auto lua_to<lua_Number>(lua_State* L, int index)
+{
+    return lua_tonumber(L, index);
+}
+
+template <>
+inline
+auto lua_to<std::string>(lua_State* L, int index)
+{
+    return lua_tostdstring(L, index);
+}
+
+template <>
+inline
+auto lua_to<void*>(lua_State* L, int index)
+{
+    return lua_touserdata(L, index);
+}
+
+/*****************************************************************************
+*   field operations
+*****************************************************************************/
+// return to C++, from table at index, the value of field k
+template <typename T>
+auto lua_getfieldv(lua_State* L, int index, const char* k)
+{
+    luaL_checkstack(L, 1, nullptr);
+    lua_getfield(L, index, k);
+    LuaPopper pop(L, 1);
+    return lua_to<T>(L, -1);
+}
+
+// set in table at index, as field k, the specified C++ value
+template <typename T>
+auto lua_setfieldv(lua_State* L, int index, const char* k, const T& value)
+{
+    luaL_checkstack(L, 1, nullptr);
+    lua_push(L, value);
+    lua_setfield(L, index, k);
+}
+
+// return to C++, from table at index, the value of field k (without metamethods)
+template <typename T>
+auto lua_rawgetfield(lua_State* L, int index, const std::string_view& k)
+{
+    luaL_checkstack(L, 1, nullptr);
+    lua_pushlstring(L, k.data(), k.length());
+    lua_rawget(L, index);
+    LuaPopper pop(L, 1);
+    return lua_to<T>(L, -1);
+}
+
+// set in table at index, as field k, the specified C++ value (without metamethods)
+template <typename T>
+void lua_rawsetfield(lua_State* L, int index, const std::string_view& k, const T& value)
+{
+    luaL_checkstack(L, 2, nullptr);
+    lua_pushlstring(L, k.data(), k.length());
+    lua_push(L, value);
+    lua_rawset(L, index);
+}
+
 /*****************************************************************************
 *   lua_function (and helper class LuaFunction)
 *****************************************************************************/
-- 
cgit v1.2.3