Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Makefile
CMakeCache.txt
CMakeFiles/
build/
Build/
*.dir/
*.sln
*.vcxproj
Expand Down
119 changes: 119 additions & 0 deletions Distribution/LuaBridge/LuaBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -2746,6 +2746,16 @@ template <class T, auto = typeName<T>().find_first_of('.')>
return reinterpret_cast<void*>(0x8108);
}

[[nodiscard]] inline const void* getStaticIndexFallbackKey()
{
return reinterpret_cast<void*>(0x81cc);
}

[[nodiscard]] inline const void* getStaticNewIndexFallbackKey()
{
return reinterpret_cast<void*>(0x8109);
}

template <class T>
[[nodiscard]] const void* getStaticRegistryKey() noexcept
{
Expand Down Expand Up @@ -6188,6 +6198,30 @@ inline std::optional<int> try_call_index_fallback(lua_State* L)
return std::nullopt;
}

inline std::optional<int> try_call_static_index_fallback(lua_State* L)
{
LUABRIDGE_ASSERT(lua_istable(L, -1));

lua_rawgetp_x(L, -1, getStaticIndexFallbackKey());
if (! lua_iscfunction(L, -1))
{
lua_pop(L, 1);
return std::nullopt;
}

lua_pushvalue(L, 2);
lua_call(L, 1, 1);

if (! lua_isnoneornil(L, -1))
{
lua_remove(L, -2);
return 1;
}

lua_pop(L, 1);
return std::nullopt;
}

template <bool IsObject>
inline std::optional<int> try_call_index_extensible(lua_State* L, const char* key)
{
Expand Down Expand Up @@ -6239,6 +6273,12 @@ inline int index_metamethod(lua_State* L)
if (auto result = try_call_index_fallback(L))
return *result;
}
else
{

if (auto result = try_call_static_index_fallback(L))
return *result;
}

if (lua_istable(L, 1))
{
Expand Down Expand Up @@ -6354,6 +6394,24 @@ inline std::optional<int> try_call_newindex_fallback(lua_State* L)
return 0;
}

inline std::optional<int> try_call_static_newindex_fallback(lua_State* L)
{
LUABRIDGE_ASSERT(lua_istable(L, -1));

lua_rawgetp_x(L, -1, getStaticNewIndexFallbackKey());
if (! lua_iscfunction(L, -1))
{
lua_pop(L, 1);
return std::nullopt;
}

lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_call(L, 2, 0);

return 0;
}

inline std::optional<int> try_call_newindex_extensible(lua_State* L, const char* key)
{
LUABRIDGE_ASSERT(key != nullptr);
Expand Down Expand Up @@ -6525,6 +6583,9 @@ inline int newindex_metamethod(lua_State* L)
else
{

if (auto result = try_call_static_newindex_fallback(L))
return *result;

if (options.test(extensibleClass))
{
if (auto result = try_call_newindex_extensible(L, key))
Expand Down Expand Up @@ -9600,6 +9661,64 @@ class Namespace : public detail::Registrar
return *this;
}

template <class Function>
auto addStaticIndexMetaMethod(Function function)
-> std::enable_if_t<!std::is_pointer_v<Function>
&& std::is_invocable_v<Function, const LuaRef&, lua_State*>, Class<T>&>
{
using FnType = decltype(function);

assertStackState();

lua_newuserdata_aligned<FnType>(L, std::move(function));
lua_pushcclosure_x(L, &detail::invoke_proxy_functor<FnType>, "__index", 1);
lua_rawsetp_x(L, -2, detail::getStaticIndexFallbackKey());

return *this;
}

Class<T>& addStaticIndexMetaMethod(LuaRef (*idxf)(const LuaRef&, lua_State*))
{
using FnType = decltype(idxf);

assertStackState();

lua_pushlightuserdata(L, reinterpret_cast<void*>(idxf));
lua_pushcclosure_x(L, &detail::invoke_proxy_function<FnType>, "__index", 1);
lua_rawsetp_x(L, -2, detail::getStaticIndexFallbackKey());

return *this;
}

template <class Function>
auto addStaticNewIndexMetaMethod(Function function)
-> std::enable_if_t<!std::is_pointer_v<Function>
&& std::is_invocable_v<Function, const LuaRef&, const LuaRef&, lua_State*>, Class<T>&>
{
using FnType = decltype(function);

assertStackState();

lua_newuserdata_aligned<FnType>(L, std::move(function));
lua_pushcclosure_x(L, &detail::invoke_proxy_functor<FnType>, "__newindex", 1);
lua_rawsetp_x(L, -2, detail::getStaticNewIndexFallbackKey());

return *this;
}

Class<T>& addStaticNewIndexMetaMethod(LuaRef (*idxf)(const LuaRef&, const LuaRef&, lua_State*))
{
using FnType = decltype(idxf);

assertStackState();

lua_pushlightuserdata(L, reinterpret_cast<void*>(idxf));
lua_pushcclosure_x(L, &detail::invoke_proxy_function<FnType>, "__newindex", 1);
lua_rawsetp_x(L, -2, detail::getStaticNewIndexFallbackKey());

return *this;
}

template <class Getter>
Class<T>& addProperty(const char* name, Getter getter, bool) = delete;

Expand Down
52 changes: 52 additions & 0 deletions Source/LuaBridge/detail/CFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,30 @@ inline std::optional<int> try_call_index_fallback(lua_State* L)
return std::nullopt;
}

inline std::optional<int> try_call_static_index_fallback(lua_State* L)
{
LUABRIDGE_ASSERT(lua_istable(L, -1)); // Stack: mt

lua_rawgetp_x(L, -1, getStaticIndexFallbackKey()); // Stack: mt, ifb (may be nil)
if (! lua_iscfunction(L, -1))
{
lua_pop(L, 1); // Stack: mt
return std::nullopt;
}

lua_pushvalue(L, 2); // Stack: mt, ifb, arg1 (key only, no self for static)
lua_call(L, 1, 1); // Stack: mt, ifbresult

if (! lua_isnoneornil(L, -1))
{
lua_remove(L, -2); // Stack: ifbresult
return 1;
}

lua_pop(L, 1); // Stack: mt
return std::nullopt;
}

template <bool IsObject>
inline std::optional<int> try_call_index_extensible(lua_State* L, const char* key)
{
Expand Down Expand Up @@ -292,6 +316,12 @@ inline int index_metamethod(lua_State* L)
if (auto result = try_call_index_fallback(L))
return *result;
}
else
{
// Repeat the lookup in the static index fallback
if (auto result = try_call_static_index_fallback(L))
return *result;
}

// Search into self or metatable
if (lua_istable(L, 1))
Expand Down Expand Up @@ -424,6 +454,24 @@ inline std::optional<int> try_call_newindex_fallback(lua_State* L)
return 0;
}

inline std::optional<int> try_call_static_newindex_fallback(lua_State* L)
{
LUABRIDGE_ASSERT(lua_istable(L, -1)); // Stack: mt

lua_rawgetp_x(L, -1, getStaticNewIndexFallbackKey()); // Stack: mt, nifb (may be nil)
if (! lua_iscfunction(L, -1))
{
lua_pop(L, 1); // Stack: mt
return std::nullopt;
}

lua_pushvalue(L, 2); // stack: mt, nifb, arg1 (key only, no self for static)
lua_pushvalue(L, 3); // stack: mt, nifb, arg1, arg2 (value)
lua_call(L, 2, 0); // stack: mt

return 0;
}

inline std::optional<int> try_call_newindex_extensible(lua_State* L, const char* key)
{
LUABRIDGE_ASSERT(key != nullptr);
Expand Down Expand Up @@ -610,6 +658,10 @@ inline int newindex_metamethod(lua_State* L)
}
else
{
// Try in the static new index fallback
if (auto result = try_call_static_newindex_fallback(L))
return *result;

// Try in the new index extensible
if (options.test(extensibleClass))
{
Expand Down
18 changes: 18 additions & 0 deletions Source/LuaBridge/detail/ClassInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,24 @@ template <class T, auto = typeName<T>().find_first_of('.')>
return reinterpret_cast<void*>(0x8108);
}

//=================================================================================================
/**
* The key of the static index fall back in another metatable.
*/
[[nodiscard]] inline const void* getStaticIndexFallbackKey()
{
return reinterpret_cast<void*>(0x81cc);
}

//=================================================================================================
/**
* The key of the static new index fall back in another metatable.
*/
[[nodiscard]] inline const void* getStaticNewIndexFallbackKey()
{
return reinterpret_cast<void*>(0x8109);
}

//=================================================================================================
/**
* @brief Get the key for the static table in the Lua registry.
Expand Down
70 changes: 70 additions & 0 deletions Source/LuaBridge/detail/Namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,76 @@ class Namespace : public detail::Registrar
return *this;
}

//=========================================================================================
/**
* @brief Add a static index metamethod function fallback that is triggered when no result is found in static functions, properties or any other static members.
*
* Let the user define a fallback index (__index) metamethod for the static class table.
*/
template <class Function>
auto addStaticIndexMetaMethod(Function function)
-> std::enable_if_t<!std::is_pointer_v<Function>
&& std::is_invocable_v<Function, const LuaRef&, lua_State*>, Class<T>&>
{
using FnType = decltype(function);

assertStackState(); // Stack: const table (co), class table (cl), static table (st)

lua_newuserdata_aligned<FnType>(L, std::move(function)); // Stack: co, cl, st, function userdata (ud)
lua_pushcclosure_x(L, &detail::invoke_proxy_functor<FnType>, "__index", 1); // Stack: co, cl, st, function
lua_rawsetp_x(L, -2, detail::getStaticIndexFallbackKey());

return *this;
}

Class<T>& addStaticIndexMetaMethod(LuaRef (*idxf)(const LuaRef&, lua_State*))
{
using FnType = decltype(idxf);

assertStackState(); // Stack: const table (co), class table (cl), static table (st)

lua_pushlightuserdata(L, reinterpret_cast<void*>(idxf)); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_proxy_function<FnType>, "__index", 1); // Stack: co, cl, st, function
lua_rawsetp_x(L, -2, detail::getStaticIndexFallbackKey());

return *this;
}

//=========================================================================================
/**
* @brief Add a static new index metamethod function fallback that is triggered when no result is found in static functions, properties or any other static members.
*
* Let the user define a fallback new index (__newindex) metamethod for the static class table.
*/
template <class Function>
auto addStaticNewIndexMetaMethod(Function function)
-> std::enable_if_t<!std::is_pointer_v<Function>
&& std::is_invocable_v<Function, const LuaRef&, const LuaRef&, lua_State*>, Class<T>&>
{
using FnType = decltype(function);

assertStackState(); // Stack: const table (co), class table (cl), static table (st)

lua_newuserdata_aligned<FnType>(L, std::move(function)); // Stack: co, cl, st, function userdata (ud)
lua_pushcclosure_x(L, &detail::invoke_proxy_functor<FnType>, "__newindex", 1); // Stack: co, cl, st, function
lua_rawsetp_x(L, -2, detail::getStaticNewIndexFallbackKey());

return *this;
}

Class<T>& addStaticNewIndexMetaMethod(LuaRef (*idxf)(const LuaRef&, const LuaRef&, lua_State*))
{
using FnType = decltype(idxf);

assertStackState(); // Stack: const table (co), class table (cl), static table (st)

lua_pushlightuserdata(L, reinterpret_cast<void*>(idxf)); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_proxy_function<FnType>, "__newindex", 1); // Stack: co, cl, st, function
lua_rawsetp_x(L, -2, detail::getStaticNewIndexFallbackKey());

return *this;
}

//=========================================================================================
/**
* @brief Add or replace a property member, by constructible by std::function.
Expand Down
Loading