Closed etorth closed 1 year ago
I prepared pice of code that can compile:
#include <memory>
#include <iostream>
#include <sstream>
#include <string>
#include <ostream>
#include <cstddef>
#include <variant>
#include <unordered_map>
#include <type_traits>
#include <sol/sol.hpp>
template<typename... Ts> struct luaVarDispatcher: Ts...
{
using Ts::operator()...;
};
struct luaNil
{
bool operator == (const luaNil &) const
{
return true;
}
};
class luaVarWrapper;
namespace _details
{
struct _luaVarWrapperHash
{
size_t operator() (const luaVarWrapper &) const noexcept;
};
}
class luaVarWrapper;
using luaTable = std::unordered_map<luaVarWrapper, luaVarWrapper, _details::_luaVarWrapperHash>;
using luaVar = std::variant<
luaNil,
luaTable,
lua_Integer,
double,
bool,
std::string>;
class luaVarWrapper
{
private:
friend struct _details::_luaVarWrapperHash;
private:
std::unique_ptr<luaVar> m_ptr;
public:
/**/ luaVarWrapper() = default;
/**/ ~luaVarWrapper() = default;
public:
template<typename T> luaVarWrapper(T t)
: m_ptr(std::make_unique<luaVar>(std::move(t)))
{}
public:
luaVarWrapper(luaNil)
: luaVarWrapper()
{}
public:
luaVarWrapper(luaVar v): m_ptr(std::visit(luaVarDispatcher
{
[](luaNil) -> std::unique_ptr<luaVar>
{
return nullptr;
},
[](auto &&arg) -> std::unique_ptr<luaVar>
{
return std::make_unique<luaVar>(std::move(arg));
},
}, std::move(v))){}
public:
luaVarWrapper(const luaVarWrapper &w)
: m_ptr(w.m_ptr ? std::make_unique<luaVar>(*w.m_ptr) : nullptr)
{}
luaVarWrapper(luaVarWrapper &&w)
: m_ptr(std::move(w.m_ptr))
{}
luaVarWrapper & operator = (luaVarWrapper w)
{
std::swap(m_ptr, w.m_ptr);
return *this;
}
public:
operator luaVar () const
{
if(m_ptr){
return *m_ptr;
}
else{
return luaNil{};
}
}
public:
/* */ luaVar &get() { return *m_ptr; }
const luaVar &get() const { return *m_ptr; }
public:
bool operator == (const luaVarWrapper &parm) const
{
if(m_ptr){
return get() == parm.get();
}
else{
return parm.m_ptr == nullptr; // luaNil
}
}
bool operator == (const luaVar &parm) const
{
if(m_ptr){
return get() == parm;
}
else{
return parm.index() == 0; // luaNil
}
}
bool operator == (const luaNil &) const
{
return m_ptr == nullptr || m_ptr->index() == 0;
}
};
size_t _details::_luaVarWrapperHash::operator () (const luaVarWrapper &wrapper) const noexcept
{
return std::visit(luaVarDispatcher
{
[](const luaNil &) -> size_t
{
return 2918357;
},
[](const luaTable &table) -> size_t // requires order-invariant
{
size_t h = 3679231;
for(const auto &[k, v]: table){
h ^= _details::_luaVarWrapperHash{}(k);
h ^= _details::_luaVarWrapperHash{}(v);
}
return h;
},
[](const auto &t) -> size_t
{
return std::hash<std::remove_cvref_t<decltype(t)>>{}(t);
},
}, *wrapper.m_ptr);
}
template<typename T> sol::object buildLuaObj(sol::state_view sv, T t)
{
return sol::object(sv, sol::in_place_type<std::remove_cvref_t<decltype(t)>>, std::move(t));
}
sol::object buildLuaObj(sol::state_view sv, luaNil)
{
return sol::make_object(sv, sol::nil);
}
sol::object buildLuaObj(sol::state_view sv, luaVar v)
{
return std::visit(luaVarDispatcher
{
[&sv](const luaTable &t) -> sol::object
{
sol::table tbl(sv.lua_state(), sol::create);
for(const auto &[k, v]: t){
tbl[buildLuaObj(sv, k)] = buildLuaObj(sv, v);
}
return tbl; // sol::table can be used as sol::object
},
[&sv](const auto &v) -> sol::object
{
return buildLuaObj(sv, v);
}
}, v);
}
luaTable makeLuaTable(std::initializer_list<luaVar> elems)
{
luaTable table;
lua_Integer index = 1;
for(const auto &e: elems){
table[luaVar(index++)] = luaVar(e);
}
return table;
}
int main()
{
// { {1, 2}, {3, 4}, {5, 6} }
luaVar tbl = makeLuaTable({
makeLuaTable({
1,
2,
}),
makeLuaTable({
3,
4,
}),
makeLuaTable({
5,
6,
}),
});
sol::state lua;
lua.open_libraries();
lua.set_function("func", [tbl](sol::function handler, sol::this_state s)
{
sol::object obj = buildLuaObj(sol::state_view(s), tbl);
handler("hello", obj);
});
sol::protected_function_result pfr = lua.script(R"#(
local function handler(msg, tbl)
local printTable = nil
printTable = function(prefix, t)
print(prefix, t, type(t))
for k, v in pairs(t) do
printTable(prefix .. ' ', v)
end
end
printTable('', tbl)
end
func(handler)
)#");
if(!pfr.valid()){
const sol::error err = pfr;
std::stringstream errStream(err.what());
std::string errStr;
while(std::getline(errStream, errStr, '\n')){
std::cout << errStr << std::endl;
}
}
return 0;
}
output is:
table: 0x7fffd6fa0e70 table
sol.luaVarWrapper: 0x7fffd6fa30f8 userdata
You see the first layer is table``, but nested table are
userdata`` and can not iterate.
my fault! I didn't explicitly declare buildLuaObj(luaVarWrapper) which makes the trouble.
I am trying to convert a resursive
std::variant
to asol::object
. Code looks like following but more details needed, you can check link here if you need:https://github.com/etorth/mir2x/blob/a640d319854ad751ae0c3c7b1305a78d06ea376f/common/src/luaf.cpp#L72
Then if the
luaVar
is a nested table, likeThen I use
buildLuaObj()
to convert above table into asol::object
, when I passed thesol::object
to lua script, the first layer is still a table. But for nested tables like{5, 6}
and{7, {8}}
, they all get parsed asuserdata
, what's more, I can not iterate theseuserdata
s.Does sol2 forget to recursively create table for lua, or something is wrong in my code? Thanks!