return std::string_view(key, size);
}
+template<typename T, int uv=0>
+void pushreftype(lua_State *L, auto&&... args) {
+ new (lua_newuserdatauv(L, sizeof(T), uv)) T(std::forward<decltype(args)>(args)...);
+ luaL_setmetatable(L, T::mtname);
+}
+
template<typename T>
struct MptrOwnerType {};
template<typename T, typename U>
template<auto P> // <int(T::* P)(lua_State *L)>
int LuaForwarder(lua_State *L) {
using T = MptrOwnerType<decltype(P)>::type;
- return (static_cast<T*>(luaL_checkudata(L, 1, T::mtname()))->*P)(L);
+ return (static_cast<T*>(luaL_checkudata(L, 1, T::mtname))->*P)(L);
+}
+
+static void push(lua_State *L, std::string_view sv) {
+ lua_pushlstring(L, sv.data(), sv.size());
+}
+static void push(lua_State *L, const std::string &s) {
+ push(L, std::string_view(s));
}
+static void push(lua_State *L, Client *cl);
+static void push(lua_State *L, Channel *chan);
template<typename T>
struct SetRef {
map_base2<T> &s;
- static consteval const char *mtname() {
+ static consteval const char *get_mtname() {
if constexpr (std::same_as<T, std::string>) {
return "Set<std::string>";
} else if constexpr (std::same_as<T, Client*>) {
static_assert(false);
}
};
- static void pushval(lua_State *L, const T& v) requires std::same_as<T, std::string> {
- lua_pushlstring(L, v.data(), v.size());
- }
- static void pushval(lua_State *L, const T& v) requires std::same_as<T, Client*> {
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = v;
- luaL_setmetatable(L, "Client");
- }
- static void pushval(lua_State *L, const T& v) requires std::same_as<T, Channel*> {
- *(Channel **)lua_newuserdatauv(L, sizeof(Channel *), 0) = v;
- luaL_setmetatable(L, "Channel");
- }
+ static constexpr const char *mtname = get_mtname();
int index(lua_State *L) {
std::string_view key = checkstringview(L, 2);
if (!s.has(key))
return 0;
- pushval(L, s.get(key));
+ push(L, s.get(key));
return 1;
}
int newindex(lua_State *L) {
return 0;
}
struct Iter {
- static consteval const char *mtname() {
+ static consteval const char *get_mtname() {
if constexpr (std::same_as<T, std::string>) {
return "Set<std::string>::Iter";
} else if constexpr (std::same_as<T, Client*>) {
static_assert(false);
}
};
+ static constexpr const char *mtname = get_mtname();
size_t index = 0;
int next(lua_State *L) {
lua_getiuservalue(L, 1, 1);
- SetRef &ref = *(SetRef *)lua_touserdata(L, -1);
+ SetRef &ref = *static_cast<SetRef *>(lua_touserdata(L, -1));
auto &m = ref.s.m;
auto it = m.begin() + index;
if (it == m.end())
return 0;
index++;
- auto key = to_key(*it);
- lua_pushlstring(L, key.data(), key.size());
- pushval(L, *it);
+ push(L, to_key(*it));
+ push(L, *it);
return 2;
}
};
int pairs(lua_State *L) {
lua_pushcfunction(L, LuaForwarder<&Iter::next>);
- new (lua_newuserdatauv(L, sizeof(Iter), 1)) Iter();
- luaL_setmetatable(L, Iter::mtname());
+ pushreftype<Iter, 1>(L);
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, 1);
lua_pushnil(L);
return 3;
}
- static void push(lua_State *L, map_base2<T> *s) {
- new (lua_newuserdatauv(L, sizeof(SetRef), 0)) SetRef(*s);
- luaL_setmetatable(L, mtname());
+ static void _push(lua_State *L, map_base2<T> &s) {
+ pushreftype<SetRef>(L, s);
}
static void regmt(lua_State *L) {
- if (luaL_newmetatable(L, mtname())) {
+ if (luaL_newmetatable(L, mtname)) {
luaL_Reg funcs[] = {
{"__index", LuaForwarder<&SetRef::index>},
{"__newindex", LuaForwarder<&SetRef::newindex>},
luaL_setfuncs(L, funcs, 0);
}
lua_pop(L, 1);
- luaL_newmetatable(L, Iter::mtname());
+ luaL_newmetatable(L, Iter::mtname);
lua_pop(L, 1);
}
};
template<typename T>
-static void SetRef_push(lua_State *L, map_base2<T> *s) {
- SetRef<T>::push(L, s);
+static void push(lua_State *L, map_base2<T> &s) {
+ SetRef<T>::_push(L, s);
}
-static int client_index(lua_State *L)
-{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
- const char *key = luaL_checkstring(L, 2);
- if (!cl)
- return 0;
-#define string_getter(c, s) if (!strcmp(key, #s)) return lua_pushstring(L, c->s), 1
-#define integer_getter(c, s) if (!strcmp(key, #s)) return lua_pushinteger(L, c->s), 1
-#define SetRef_getter(c, s) if (!strcmp(key, #s)) return SetRef_push(L, &c->s), 1
- integer_getter(cl, fd);
- /* cctx */
- if (!strcmp(key, "next")) {
- if (!cl->next)
+struct ClientRef {
+ Client *cl;
+ static constexpr const char *mtname = "Client";
+ friend void push(lua_State *L, Client *cl) {
+ pushreftype<ClientRef>(L, cl);
+ }
+ static Client *check(lua_State *L, int idx) {
+ return static_cast<ClientRef *>(luaL_checkudata(L, idx, mtname))->cl;
+ }
+ int index(lua_State *L) {
+ auto key = checkstringview(L, 2);
+ if (!cl)
return 0;
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = cl->next;
- luaL_setmetatable(L, "Client");
- return 1;
+#define string_getter(c, s) if (key == #s##sv) return lua_pushstring(L, c->s), 1
+#define integer_getter(c, s) if (key == #s##sv) return lua_pushinteger(L, c->s), 1
+#define SetRef_getter(c, s) if (key == #s##sv) return push(L, c->s), 1
+ integer_getter(cl, fd);
+ /* cctx */
+ if (key == "next"sv) {
+ if (!cl->next)
+ return 0;
+ return push(L, cl->next), 1;
+ }
+ string_getter(cl, nick);
+ string_getter(cl, key);
+ string_getter(cl, username);
+ string_getter(cl, realname);
+ string_getter(cl, hostname);
+ string_getter(cl, nuh);
+ string_getter(cl, away);
+ string_getter(cl, nick_reg);
+ /* string_getter(cl, pass_reg); */
+ string_getter(cl, peername);
+ integer_getter(cl, peerport);
+ /* saslbuf */
+ /* saslbufLen */
+ /* saslusername */
+ /* webircpeername */
+ /* webirchostname */
+ /* rbuf/rlen/wbuf/wlen */
+ integer_getter(cl, umode);
+ integer_getter(cl, regstate);
+ SetRef_getter(cl, channels);
+ SetRef_getter(cl, invites);
+ SetRef_getter(cl, monitor);
+ integer_getter(cl, cookie);
+ integer_getter(cl, signon);
+ integer_getter(cl, lastactivity);
+ integer_getter(cl, caps);
+ integer_getter(cl, want_write_for_read);
+ integer_getter(cl, want_read_for_write);
+ integer_getter(cl, want_write_for_write);
+ integer_getter(cl, want_read_for_close);
+ integer_getter(cl, want_write_for_close);
+ integer_getter(cl, dying);
+ integer_getter(cl, write_error);
+ integer_getter(cl, poll_reg);
+ /* saslexternal */
+ /* passwait */
+ /* webircwait */
+ return 0;
}
- string_getter(cl, nick);
- string_getter(cl, key);
- string_getter(cl, username);
- string_getter(cl, realname);
- string_getter(cl, hostname);
- string_getter(cl, nuh);
- string_getter(cl, away);
- string_getter(cl, nick_reg);
- /* string_getter(cl, pass_reg); */
- string_getter(cl, peername);
- integer_getter(cl, peerport);
- /* saslbuf */
- /* saslbufLen */
- /* saslusername */
- /* webircpeername */
- /* webirchostname */
- /* rbuf/rlen/wbuf/wlen */
- integer_getter(cl, umode);
- integer_getter(cl, regstate);
- SetRef_getter(cl, channels);
- SetRef_getter(cl, invites);
- SetRef_getter(cl, monitor);
- integer_getter(cl, cookie);
- integer_getter(cl, signon);
- integer_getter(cl, lastactivity);
- integer_getter(cl, caps);
- integer_getter(cl, want_write_for_read);
- integer_getter(cl, want_read_for_write);
- integer_getter(cl, want_write_for_write);
- integer_getter(cl, want_read_for_close);
- integer_getter(cl, want_write_for_close);
- integer_getter(cl, dying);
- integer_getter(cl, write_error);
- integer_getter(cl, poll_reg);
- /* saslexternal */
- /* passwait */
- /* webircwait */
- return 0;
-}
-static int channel_index(lua_State *L)
-{
- Channel *chan = *(Channel **)luaL_checkudata(L, 1, "Channel");
- const char *key = luaL_checkstring(L, 2);
- if (!chan)
+ static void regmt(lua_State *L) {
+ if (luaL_newmetatable(L, mtname)) {
+ luaL_Reg funcs[] = {
+ {"__index", LuaForwarder<&ClientRef::index>},
+ {0, 0},
+ };
+ luaL_setfuncs(L, funcs, 0);
+ }
+ lua_pop(L, 1);
+ }
+};
+struct ChannelRef {
+ Channel *chan;
+ static constexpr const char *mtname = "Client";
+ friend void push(lua_State *L, Channel *chan) {
+ pushreftype<ChannelRef>(L, chan);
+ }
+ static Channel *check(lua_State *L, int idx) {
+ return static_cast<ChannelRef *>(luaL_checkudata(L, idx, mtname))->chan;
+ }
+ int index(lua_State *L) {
+ auto key = checkstringview(L, 2);
+ if (!chan)
+ return 0;
+ string_getter(chan, key);
+ string_getter(chan, name);
+ string_getter(chan, topic);
+ string_getter(chan, topic_who);
+ integer_getter(chan, topic_when);
+ integer_getter(chan, creation);
+ SetRef_getter(chan, members);
+ SetRef_getter(chan, o);
+ SetRef_getter(chan, v);
+ integer_getter(chan, member_count);
+ integer_getter(chan, dmode);
+ SetRef_getter(chan, listb);
+ SetRef_getter(chan, liste);
+ SetRef_getter(chan, listI);
+ SetRef_getter(chan, listq);
+ SetRef_getter(chan, listwo);
+ SetRef_getter(chan, listwv);
+ SetRef_getter(chan, invitees);
+ string_getter(chan, chankey);
+ integer_getter(chan, member_limit);
return 0;
- string_getter(chan, key);
- string_getter(chan, name);
- string_getter(chan, topic);
- string_getter(chan, topic_who);
- integer_getter(chan, topic_when);
- integer_getter(chan, creation);
- SetRef_getter(chan, members);
- SetRef_getter(chan, o);
- SetRef_getter(chan, v);
- integer_getter(chan, member_count);
- integer_getter(chan, dmode);
- SetRef_getter(chan, listb);
- SetRef_getter(chan, liste);
- SetRef_getter(chan, listI);
- SetRef_getter(chan, listq);
- SetRef_getter(chan, listwo);
- SetRef_getter(chan, listwv);
- SetRef_getter(chan, invitees);
- string_getter(chan, chankey);
- integer_getter(chan, member_limit);
- return 0;
-}
-static int globals_index(lua_State *L)
-{
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "client_map"))
- return SetRef_push(L, &client_map), 1;
- if (!strcmp(key, "channel_map"))
- return SetRef_push(L, &channel_map), 1;
- if (!strcmp(key, "clients")) {
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = clients;
- luaL_setmetatable(L, "Client");
- return 1;
}
- if (!strcmp(key, "dyingclients")) {
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = dyingclients;
- luaL_setmetatable(L, "Client");
- return 1;
+ static void regmt(lua_State *L) {
+ if (luaL_newmetatable(L, mtname)) {
+ luaL_Reg funcs[] = {
+ {"__index", LuaForwarder<&ChannelRef::index>},
+ {0, 0},
+ };
+ luaL_setfuncs(L, funcs, 0);
+ }
+ lua_pop(L, 1);
}
+};
+static int globals_index(lua_State *L)
+{
+ auto key = checkstringview(L, 2);
+ if (key == "client_map"sv)
+ return push(L, client_map), 1;
+ if (key == "channel_map"sv)
+ return push(L, channel_map), 1;
+ if (key == "clients"sv)
+ return push(L, clients), 1;
+ if (key == "dyingclients"sv)
+ return push(L, dyingclients), 1;
return 0;
}
static int command_eval(lua_State *L)
}
static int fn_client_privmsg(lua_State *L)
{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
+ Client *cl = ClientRef::check(L, 1);
const char *msg = luaL_checkstring(L, 2);
msg_privmsg_server(luaL_optstring(L, 3, hostname), cl->nick, msg), sendbuf(cl);
return 0;
}
static int fn_client_notice(lua_State *L)
{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
+ Client *cl = ClientRef::check(L, 1);
const char *msg = luaL_checkstring(L, 2);
msg_notice_server(luaL_optstring(L, 3, hostname), cl->nick, msg), sendbuf(cl);
return 0;
}
static int fn_channel_join(lua_State *L)
{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
+ Client *cl = ClientRef::check(L, 1);
const char *channel = 0;
Channel *chan = 0;
if (lua_isuserdata(L, 2)) {
- chan = *(Channel **)luaL_checkudata(L, 2, "Channel");
+ chan = ChannelRef::check(L, 2);
channel = chan->key;
} else {
channel = luaL_checkstring(L, 2);
}
static int fn_channel_part(lua_State *L)
{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
- Channel *chan = *(Channel **)luaL_checkudata(L, 2, "Channel");
+ Client *cl = ClientRef::check(L, 1);
+ Channel *chan = ChannelRef::check(L, 2);
const char *reason = luaL_optstring(L, 3, 0);
Client *kicker = 0;
if (lua_isuserdata(L, 4))
- kicker = *(Client **)luaL_checkudata(L, 4, "Client");
+ kicker = ClientRef::check(L, 4);
channel_part(cl, chan, reason, kicker);
return 0;
}
}
static int fn_channel_mode(lua_State *L)
{
- Channel *chan = *(Channel **)luaL_checkudata(L, 1, "Channel");
+ Channel *chan = ChannelRef::check(L, 1);
size_t as, bs;
const char *a = luaL_checklstring(L, 2, &as);
const char *b = luaL_optlstring(L, 3, 0, &bs);
}
static int fn_channel_topic(lua_State *L)
{
- Channel *chan = *(Channel **)luaL_checkudata(L, 1, "Channel");
+ Channel *chan = ChannelRef::check(L, 1);
const char *topic = luaL_checkstring(L, 2);
const char *who = luaL_checkstring(L, 3);
time_t when = luaL_optinteger(L, 4, 0);
}
static int fn_client_chghost(lua_State *L)
{
- Client *cl = *(Client **)luaL_checkudata(L, 1, "Client");
+ Client *cl = ClientRef::check(L, 1);
const char *newusername = luaL_optstring(L, 2, 0);
const char *newhostname = luaL_optstring(L, 3, 0);
client_chghost(cl, newusername, newhostname);
return 0;
}
static int fn_rpl_whoisspecial(lua_State *L) {
- Client *cl1 = *(Client **)luaL_checkudata(L, 1, "Client");
- Client *cl2 = *(Client **)luaL_checkudata(L, 2, "Client");
+ Client *cl1 = ClientRef::check(L, 1);
+ Client *cl2 = ClientRef::check(L, 2);
const char *text = luaL_checkstring(L, 3);
rpl_whoisspecial(cl1, cl2, "", text), sendbuf(cl1);
return 0;
lua_pushinteger(L, stmt.num(i));
} else {
auto sv = stmt.text(i);
- if (sv.data())
- lua_pushlstring(L, sv.data(), sv.size());
- else
- lua_pushnil(L);
+ sv.data() ? push(L, sv) : lua_pushnil(L);
}
lua_rawseti(L, -2, i+1);
}
SetRef<std::string>::regmt(L);
SetRef<Client *>::regmt(L);
SetRef<Channel *>::regmt(L);
- if (luaL_newmetatable(L, "Client")) {
- luaL_Reg funcs[] = {
- {"__index", client_index},
- {0, 0},
- };
- luaL_setfuncs(L, funcs, 0);
- }
- lua_pop(L, 1);
- if (luaL_newmetatable(L, "Channel")) {
- luaL_Reg funcs[] = {
- {"__index", channel_index},
- {0, 0},
- };
- luaL_setfuncs(L, funcs, 0);
- }
- lua_pop(L, 1);
+ ClientRef::regmt(L);
+ ChannelRef::regmt(L);
if (luaL_newmetatable(L, "globals")) {
luaL_Reg funcs[] = {
{"__index", globals_index},
lua_pop(L, 1);
return false;
}
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = client;
- luaL_setmetatable(L, "Client");
+ push(L, client);
lua_pushstring(L, source);
lua_pushstring(L, command);
lua_createtable(L, argc, 1);
return 0;
}
lua_pushstring(L, hook);
- if (cl1) {
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = cl1;
- luaL_setmetatable(L, "Client");
- } else {
- lua_pushnil(L);
- }
- if (cl2) {
- *(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = cl2;
- luaL_setmetatable(L, "Client");
- } else {
- lua_pushnil(L);
- }
- if (chan) {
- *(Channel **)lua_newuserdatauv(L, sizeof(Client *), 0) = chan;
- luaL_setmetatable(L, "Channel");
- } else {
- lua_pushnil(L);
- }
- if (txt)
- lua_pushstring(L, txt);
- else
- lua_pushnil(L);
+ cl1 ? push(L, cl1) : lua_pushnil(L);
+ cl2 ? push(L, cl2) : lua_pushnil(L);
+ chan ? push(L, chan) : lua_pushnil(L);
+ txt ? (void)lua_pushstring(L, txt) : lua_pushnil(L);
if (LUA_OK != lua_pcall(L, 5, 1, 0)) {
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1);