Reputation: 93
After multiple attempts and hours of googling I finally came to realize SOF is probably my best place to solve this.
I am currently using the Lua C API to create an extension, a shared library that you can use by requiring it via require
. I am trying to do something very similar to this (sorry about the formatting):
local data = {
something = "some"
}
local rpc = {}
function rpc.method()
print('ran')
end
function rpc.method2()
print('ran222')
end
local metatable = {}
metatable.__index = function(self, key)
return data[key]
end
setmetatable(rpc, metatable)
--------------------------------------------
rpc.method()
print(rpc['something'])
rpc.method2()
My current C code look something like this:
static int lua_index(lua_State* lua) { //idk
std::cout << "Was indexed";
const char* a = luaL_checkstring(lua, 2);
std::cout << a << std::endl;
return 0;
}
static int lua_initialize(lua_State* lua) {
std::cout << "ran";
return 0;
}
static const struct luaL_Reg lib[] = {
{ "initialize", lua_initialize },
{"__index", lua_index},
{ NULL, NULL }
};
extern "C" int DISCORD_RPC_EXPORT luaopen_DiscordRPC(lua_State* lua) {
luaL_newlib(lua, lib);
lua_setmetatable(lua, 1);
return 1;
}
And using this as an example:
local rpc = require "DiscordRPC"
print(rpc['a'])
rpc.initialize();
Now obviously rpc['a']
would return nil (yes lua_index
does in fact run) because lua_index
isn't doing anything but why can't I call initialize
? It clearly there. It says: lua: main.lua:5: attempt to call a nil value (field 'initialize')
So it is nil. If I would to remove lua_setmetatable(lua, 1);
I would be able to call that function but I can not index it DiscordRPC
as I want to. Also I would like to point out that when I remove it the __index
metamethod get called two times, obviously it would.
My question: how can I achieve this? I am trying to set a metatable on a table and return the entire metatable. Any help is very much appreciated as I am complete lost. Thank you.
Upvotes: 1
Views: 1644
Reputation: 188
You have to set the metatable to your table by pushing it to the top of the stack and then calling lua_setmetatable
.
luaL_newlib(lua, lib);
lua_pushvalue(lua, -1);
lua_setmetatable(lua, -2);
The call to lua_pushvalue
will push the value on position -1 (the top of the stack) to the stack again, duplicating it. Then, we call lua_setmetatable
(Documentation here doc) to pop a table on top of the stack and set it as the metatable for the table in the given index (-2, that is our lib, pushed by the luaL_newlib
command).
By doing this and running your example, I got the following results:
local rpc = require "DiscordRPC"
print(rpc['a'])
-- First, calls the __index function, printing
-- 'Was indexeda'
-- Then prints nil, since the key 'a' holds nothing
rpc.initialize();
-- Prints ran
If you have more questions towards this, I suggest you to read the chapter about Userdata and Object-Oriented Access in Programming in Lua Book.
Upvotes: 1