Skip to content

Commit

Permalink
Merge branch 'master' into dev/better_coroutine_support
Browse files Browse the repository at this point in the history
  • Loading branch information
kunitoki committed Feb 26, 2023
2 parents 1c69bf9 + 58961a3 commit 0c29ae2
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 29 deletions.
29 changes: 20 additions & 9 deletions Distribution/LuaBridge/LuaBridge.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://github.com/kunitoki/LuaBridge3
// Copyright 2022, Lucio Asnaghi
// Copyright 2023, Lucio Asnaghi
// SPDX-License-Identifier: MIT

// clang-format off
Expand Down Expand Up @@ -2871,12 +2871,11 @@ class Userdata
if (lua_isnil(L, index))
return nullptr;

return static_cast<T*>(getClass(L,
index,
detail::getConstRegistryKey<T>(),
detail::getClassRegistryKey<T>(),
canBeConst)
->getPointer());
auto* clazz = getClass(L, index, detail::getConstRegistryKey<T>(), detail::getClassRegistryKey<T>(), canBeConst);
if (! clazz)
return nullptr;

return static_cast<T*>(clazz->getPointer());
}

template <class T>
Expand Down Expand Up @@ -7651,7 +7650,7 @@ class Namespace : public detail::Registrar

if (Security::hideMetatables())
{
lua_pushnil(L);
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}
Expand Down Expand Up @@ -7706,7 +7705,7 @@ class Namespace : public detail::Registrar

if (Security::hideMetatables())
{
lua_pushnil(L);
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}
Expand Down Expand Up @@ -8671,6 +8670,12 @@ class Namespace : public detail::Registrar

lua_newtable(L);
lua_rawsetp(L, -2, detail::getPropsetKey());

if (Security::hideMetatables())
{
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}

++m_stackSize;
Expand Down Expand Up @@ -8705,6 +8710,12 @@ class Namespace : public detail::Registrar
lua_newtable(L);
lua_rawsetp(L, -2, detail::getPropsetKey());

if (Security::hideMetatables())
{
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}

lua_pushvalue(L, -1);
rawsetfield(L, -3, name);
}
Expand Down
8 changes: 4 additions & 4 deletions Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,13 @@ local a = A ()

a.func1 () -- error: func1 expects an object of a registered class
a.func1 (a) -- okay, verbose, this how OOP works in Lua
a:func1 () -- okay, less verbose, equvalent to the previous
a:func1 () -- okay, less verbose, equivalent to the previous
```

2.4 - Property Member Proxies
-----------------------------

Sometimes when registering a class which comes from a third party library, the data is not exposed in a way that can be expressed as a pointer to member, there are no get or set functions, or the get and set functons do not have the right function signature. Since the class declaration is closed for changes, LuaBridge allows for a _property member proxy_. This is a pair of get and set flat functions which take as their first parameter a pointer to the object. This is easily understood with the following example:
Sometimes when registering a class which comes from a third party library, the data is not exposed in a way that can be expressed as a pointer to member, there are no get or set functions, or the get and set functions do not have the right function signature. Since the class declaration is closed for changes, LuaBridge allows for a _property member proxy_. This is a pair of get and set flat functions which take as their first parameter a pointer to the object. This is easily understood with the following example:

```cpp
// Third party declaration, can't be changed
Expand Down Expand Up @@ -1100,7 +1100,7 @@ When a pointer or pointer to const is passed to Lua and the pointer is null (zer
3.4 - Shared Lifetime
---------------------

LuaBridge supports a _shared lifetime_ model: dynamically allocated and reference counted objects whose ownership is shared by both Lua and C++. The object remains in existence until there are no remaining C++ or Lua references, and Lua performs its usual garbage collection cycle. A container is recognized by a specialization of the `ContainerTraits` template class. LuaBridge will automatically recognize when a data type is a container when the correspoding specialization is present. Two styles of containers come with LuaBridge, including the necessary specializations.
LuaBridge supports a _shared lifetime_ model: dynamically allocated and reference counted objects whose ownership is shared by both Lua and C++. The object remains in existence until there are no remaining C++ or Lua references, and Lua performs its usual garbage collection cycle. A container is recognized by a specialization of the `ContainerTraits` template class. LuaBridge will automatically recognize when a data type is a container when the corresponding specialization is present. Two styles of containers come with LuaBridge, including the necessary specializations.

### 3.4.1 - Class RefCountedObjectPtr

Expand Down Expand Up @@ -1266,7 +1266,7 @@ Any convertible type may be assigned to an already-existing `LuaRef`:
```cpp
luabridge::LuaRef v (L); // Nil
v = luabridge::newTable (L); // An empty table
v = "string"; // A string. The prevous value becomes
v = "string"; // A string. The previous value becomes
// eligible for garbage collection.
```

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ LuaBridge3 offers a set of improvements compared to vanilla LuaBridge:
![Build Linux](https://github.com/kunitoki/LuaBridge3/workflows/Build%20Linux/badge.svg?branch=master)

## Code Coverage
[![Coverage Status](https://coveralls.io/repos/github/kunitoki/LuaBridge3/badge.svg?branch=master)](https://coveralls.io/github/kunitoki/LuaBridge3?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/kunitoki/LuaBridge3/badge.svg?branch=master&kill_cache=1)](https://coveralls.io/github/kunitoki/LuaBridge3?branch=master)

## Documentation

Expand Down
4 changes: 2 additions & 2 deletions Source/LuaBridge/detail/LuaRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ class LuaRef : public LuaRefBase<LuaRef, LuaRef>
*
* This may invoke metamethods.
*
* @tparam T The type of a value to assing.
* @tparam T The type of a value to assign.
*
* @param v A value to assign.
*
Expand Down Expand Up @@ -759,7 +759,7 @@ class LuaRef : public LuaRefBase<LuaRef, LuaRef>
*
* The assignment is raw, no metamethods are invoked.
*
* @tparam T The type of a value to assing.
* @tparam T The type of a value to assign.
*
* @param v A value to assign.
*
Expand Down
24 changes: 18 additions & 6 deletions Source/LuaBridge/detail/Namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class Namespace : public detail::Registrar

if (Security::hideMetatables())
{
lua_pushnil(L);
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}
Expand Down Expand Up @@ -250,7 +250,7 @@ class Namespace : public detail::Registrar

if (Security::hideMetatables())
{
lua_pushnil(L);
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}
Expand Down Expand Up @@ -689,7 +689,7 @@ class Namespace : public detail::Registrar
assert(name != nullptr);
assertStackState(); // Stack: const table (co), class table (cl), static table (st)

new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr
new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_const_member_function<GetType, T>, 1); // Stack: co, cl, st, getter
lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter
Expand All @@ -714,7 +714,7 @@ class Namespace : public detail::Registrar
assert(name != nullptr);
assertStackState(); // Stack: const table (co), class table (cl), static table (st)

new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr
new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_const_member_function<GetType, T>, 1); // Stack: co, cl, st, getter
lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter
Expand Down Expand Up @@ -743,7 +743,7 @@ class Namespace : public detail::Registrar
assert(name != nullptr);
assertStackState(); // Stack: const table (co), class table (cl), static table (st)

new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr
new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_const_member_function<GetType, T>, 1); // Stack: co, cl, st, getter
lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter
Expand All @@ -768,7 +768,7 @@ class Namespace : public detail::Registrar
assert(name != nullptr);
assertStackState(); // Stack: const table (co), class table (cl), static table (st)

new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr
new (lua_newuserdata_x<GetType>(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, function ptr
lua_pushcclosure_x(L, &detail::invoke_const_member_function<GetType, T>, 1); // Stack: co, cl, st, getter
lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter
Expand Down Expand Up @@ -1403,6 +1403,12 @@ class Namespace : public detail::Registrar

lua_newtable(L); // Stack: ns, mt, propset table (ps)
lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: ns

if (Security::hideMetatables())
{
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}
}

++m_stackSize;
Expand Down Expand Up @@ -1451,6 +1457,12 @@ class Namespace : public detail::Registrar
lua_newtable(L); // Stack: pns, ns, propset table (ps)
lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: pns, ns

if (Security::hideMetatables())
{
lua_pushboolean(L, 0);
rawsetfield(L, -2, "__metatable");
}

// pns [name] = ns
lua_pushvalue(L, -1); // Stack: pns, ns, ns
rawsetfield(L, -3, name); // Stack: pns, ns
Expand Down
11 changes: 5 additions & 6 deletions Source/LuaBridge/detail/Userdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,11 @@ class Userdata
if (lua_isnil(L, index))
return nullptr;

return static_cast<T*>(getClass(L,
index,
detail::getConstRegistryKey<T>(),
detail::getClassRegistryKey<T>(),
canBeConst)
->getPointer());
auto* clazz = getClass(L, index, detail::getConstRegistryKey<T>(), detail::getClassRegistryKey<T>(), canBeConst);
if (! clazz)
return nullptr;

return static_cast<T*>(clazz->getPointer());
}

template <class T>
Expand Down
53 changes: 52 additions & 1 deletion Tests/Source/ClassTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ TEST_F(ClassTests, PassOtherTypeInsteadOfNonConstThrows)

luabridge::getGlobalNamespace(L)
.beginClass<Int>("Int")
.addConstructor<void (*)(int)>() // Show that it does't matter
.addConstructor<void (*)(int)>() // Show that it doesn't matter
.endClass()
.addFunction("processNonConst", &processNonConst<int, EmptyBase>);

Expand Down Expand Up @@ -2615,3 +2615,54 @@ TEST_F(ClassTests, NewIndexFallbackMetaMethodFreeFunctor)
runLua("x.qwertyuiop = 123; result = x.qwertyuiop");
ASSERT_EQ(246, result<int>());
}

namespace {
class ExampleStringifiableClass
{
public:
ExampleStringifiableClass()
: a(0), b(0), c(0)
{
}

std::string tostring() const
{
return "whatever";
}

int a, b, c;
};
} // namespace

TEST_F(ClassTests, MetatableSecurityNotHidden)
{
luabridge::setHideMetatables(false);

luabridge::getGlobalNamespace(L)
.beginClass<ExampleStringifiableClass>("ExampleStringifiableClass")
.addConstructor<void(*) ()>()
.addFunction("__tostring", &ExampleStringifiableClass::tostring)
.endClass();

runLua("local t = ExampleStringifiableClass(); result = getmetatable(t); print(result);");

const auto res = result();
ASSERT_TRUE(res.isTable());
}

TEST_F(ClassTests, MetatableSecurity)
{
luabridge::setHideMetatables(true);

luabridge::getGlobalNamespace(L)
.beginClass<ExampleStringifiableClass>("ExampleStringifiableClass")
.addConstructor<void(*) ()>()
.addFunction("__tostring", &ExampleStringifiableClass::tostring)
.endClass();

runLua("local t = ExampleStringifiableClass(); result = getmetatable(t); print(result);");

const auto res = result();
ASSERT_TRUE(res.isBool());
EXPECT_FALSE(res.unsafe_cast<bool>());
}

0 comments on commit 0c29ae2

Please sign in to comment.