From: Egor Date: Wed, 4 Feb 2026 14:09:12 +0000 (+0200) Subject: admin: c++fication for Client/Channel bindings X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=0cdcc68163734eab87ef39b9ea7a471efda84aef;p=patchyircd.git admin: c++fication for Client/Channel bindings --- diff --git a/src/admin.cpp b/src/admin.cpp index b415b9f..4b84c90 100644 --- a/src/admin.cpp +++ b/src/admin.cpp @@ -14,6 +14,12 @@ static std::string_view checkstringview(lua_State *L, int idx) { return std::string_view(key, size); } +template +void pushreftype(lua_State *L, auto&&... args) { + new (lua_newuserdatauv(L, sizeof(T), uv)) T(std::forward(args)...); + luaL_setmetatable(L, T::mtname); +} + template struct MptrOwnerType {}; template @@ -24,14 +30,23 @@ struct MptrOwnerType { template // int LuaForwarder(lua_State *L) { using T = MptrOwnerType::type; - return (static_cast(luaL_checkudata(L, 1, T::mtname()))->*P)(L); + return (static_cast(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 struct SetRef { map_base2 &s; - static consteval const char *mtname() { + static consteval const char *get_mtname() { if constexpr (std::same_as) { return "Set"; } else if constexpr (std::same_as) { @@ -42,23 +57,13 @@ struct SetRef { static_assert(false); } }; - static void pushval(lua_State *L, const T& v) requires std::same_as { - lua_pushlstring(L, v.data(), v.size()); - } - static void pushval(lua_State *L, const T& v) requires std::same_as { - *(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 { - *(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) { @@ -80,7 +85,7 @@ struct SetRef { return 0; } struct Iter { - static consteval const char *mtname() { + static consteval const char *get_mtname() { if constexpr (std::same_as) { return "Set::Iter"; } else if constexpr (std::same_as) { @@ -91,36 +96,34 @@ struct SetRef { 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(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(L); lua_pushvalue(L, 1); lua_setiuservalue(L, -2, 1); lua_pushnil(L); return 3; } - static void push(lua_State *L, map_base2 *s) { - new (lua_newuserdatauv(L, sizeof(SetRef), 0)) SetRef(*s); - luaL_setmetatable(L, mtname()); + static void _push(lua_State *L, map_base2 &s) { + pushreftype(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>}, @@ -130,117 +133,145 @@ struct SetRef { luaL_setfuncs(L, funcs, 0); } lua_pop(L, 1); - luaL_newmetatable(L, Iter::mtname()); + luaL_newmetatable(L, Iter::mtname); lua_pop(L, 1); } }; template -static void SetRef_push(lua_State *L, map_base2 *s) { - SetRef::push(L, s); +static void push(lua_State *L, map_base2 &s) { + SetRef::_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(L, cl); + } + static Client *check(lua_State *L, int idx) { + return static_cast(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(L, chan); + } + static Channel *check(lua_State *L, int idx) { + return static_cast(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) @@ -254,25 +285,25 @@ 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); @@ -283,12 +314,12 @@ static int fn_channel_join(lua_State *L) } 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; } @@ -309,7 +340,7 @@ static int fn_channel_new(lua_State *L) } 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); @@ -324,7 +355,7 @@ static int fn_channel_mode(lua_State *L) } 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); @@ -333,15 +364,15 @@ static int fn_channel_topic(lua_State *L) } 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; @@ -382,10 +413,7 @@ static int query(lua_State *L, db::Database &db) { 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); } @@ -408,22 +436,8 @@ void admin_init(void) SetRef::regmt(L); SetRef::regmt(L); SetRef::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}, @@ -497,8 +511,7 @@ bool admin_command(Client *client, char *source, char *command, int argc, char * 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); @@ -528,28 +541,10 @@ int admin_hook(const char *hook, Client *cl1, Client *cl2, Channel *chan, char * 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);