sol2
sol2 copied to clipboard
sol not recognizing Intrusive List as a container
Hello,
I'm new to Lua and only intermediate at C++ at best, so I apologize if this is a dumb question. In short, I'm trying to access a particular Intrusive List implementation from Lua, but sol throws an error when I try to iterate on it saying that it's not recognized as a container. I read some other issue threads and saw the as_container
approach, which partially works:
typedef PCSX::Intrusive::List<Character> RoomListType;
[...]
lua.new_usertype<RoomListType>(
[](RoomListType& rl) {
return sol::as_container(rl); // Required for sol to treat Intrusive Lists as a container
}
);
sol no longer complains about it not being a container, and even allows me to iterate on it, but if I try to access any of the members on Character
from inside Lua it bombs out:
void CharacterScript::execute() {
sol::state lua;
lua.new_usertype<Character>(
"character",
"send",
&Character::send,
"room",
&Character::room, // returns a RoomListType intrusive list
"name",
&Character::name
);
lua.new_usertype<Room>(
"room",
"players",
&Room::players,
"title",
&Room::title
);
lua.new_usertype<RoomListType>(
[](RoomListType& rl) {
return sol::as_container(rl); // Required for sol to treat Intrusive Lists as a container
}
);
lua["actor"] = &m_char;
const auto& code = R"(
room = actor:room()
players = room:players()
for i = 1, #players do
actor:send(players[i]:name())
end
actor:send(room:title())
)";
lua.script(code);
Error:
[sol2] An error occurred and has been passed to an error handler: sol: runtime error: [string "..."]:5: attempt to index a nil value (field '?')
stack traceback:
[string "..."]:5: in main chunk
terminate called after throwing an instance of 'sol::error'
what(): sol: runtime error: [string "..."]:5: attempt to index a nil value (field '?')
stack traceback:
[string "..."]:5: in main chunk
Any ideas on what I'm doing wrong here? I'm confused about why the as_container
bit was necessary since I believe that intrusive list class implements all the iterator functions needed to be detected as a container.
Thanks!
If I understand correctly, containers are already understood by sol if they have many characteristics of a container.
If sol determines that a type is a container, it will automatically add a bunch of container methods to it based on the kind of container it thinks it is https://sol2.readthedocs.io/en/latest/containers.html#container-detection.
// sol should automatically detect a pushed RoomListType as a container if it seems like a container
lua.new_usertype<RoomListType>(
// also I think this new_usertype is ill formed?
[](RoomListType& list) {
return sol::as_container(list);
}
);
You should not need to create a user type for it (unless there are other con-container methods you want to add...).
Thanks, I guess my question is what is missing from the IntrusiveList
type that is causing sol not to recognize it as a container? As far as I can tell it implements the methods it needs like exposing iterators.
EDIT: The container has no proper push_back
method (it accepts a Node), which could be why it's failing.
using StringList = PCSX::Intrusive::List<std::string>;
void TestIntrusive() {
sol::state lua;
lua.open_libraries();
lua.new_usertype<StringList>("StringList",
sol::meta_function::length, &StringList::size
// other meta methods...
);
}
You can manually specify the metamethods like length and pairs..., but still not sure.
Ok so I've dug deeper into this and it's not being interpreted as a container at all, even when pushed using sol::as_container
.
I've even checked sol::is_container_v
(which returns true). I don't get why it is not working. It could be a bug (or we're idiots).
Interestingly, compilation fails when setting the global intrusive
with the std::ref and robin_hood. The PCSX list works fine though.
It's possible that the list is not being recognized because it does not contain an operator[]
. All other containers implement this, and they work. The documentation lists nothing about the index operator though (std::list
has no index operator but it works fine, not sure why not for the PCSX).
Here's a minimal test with many different things I've tried:
int main() {
sol::state lua;
lua.open_libraries();
PCSX::Intrusive::List<std::string> intrusive;
//robin_hood::unordered_map<std::string, std::string> intrusive;
lua.new_usertype<PCSX::Intrusive::List<std::string>>("Intrusive");
static_assert(sol::is_container_v<decltype(intrusive)>);
//lua["intrusive"] = std::ref(intrusive);
//lua["intrusive"] = &intrusive;
//lua["intrusive"] = sol::as_container(&intrusive);
lua["intrusive"] = sol::as_container(intrusive);
//const auto& code = R"(
// for i = 1, #intrusive do
// print(intrusive[i])
// end
//)";
const auto& code = R"(
for k, v in pairs(intrusive) do
--for k, v in intrusive:pairs() do
print(k, v)
end
)";
lua.script(code);
return 0;
}
Here's one of the errors (with all errors commonly sharing it is not recognized as a container
):
[sol2] An error occurred and has been passed to an error handler: sol: runtime error: sol: cannot call '__pairs/pairs' on type 'sol::as_container_t<PCSX::Intrusive::List<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,PCSX::Intrusive::DefaultList> >': it is not recognized as a container
stack traceback:
[C]: in ?
[C]: in function 'pairs'
[string "..."]:2: in main chunk
So, the main issue I think is that this:
lua.new_usertype<RoomListType>(
[](RoomListType& rl) {
return sol::as_container(rl); // Required for sol to treat Intrusive Lists as a container
}
);
gets never called. This binding here:
"players",
&Room::players,
which is calling
RoomListType& players() { return m_players; }
properly does its job during the Lua code room:players()
, but then after it returns, the type matching of its return type isn't triggering the RoomListType
declaration, and we end up with an untyped object, which of course can't get iterated or anything.
@ThePhD do you have any ideas on how we can make progress on this? Thanks!