degesch: refactor Lua weak objects
This commit is contained in:
parent
a9b77b3206
commit
fa5e005728
329
degesch.c
329
degesch.c
|
@ -8322,113 +8322,126 @@ lua_plugin_parse (lua_State *L)
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#define XLUA_USER_METATABLE "user" ///< Identifier for the Lua metatable
|
||||
// Lua code can use weakly referenced wrappers for internal objects.
|
||||
|
||||
struct lua_user
|
||||
typedef struct weak_ref_link *
|
||||
(*lua_weak_ref_fn) (void *object, destroy_cb_fn cb, void *user_data);
|
||||
typedef void (*lua_weak_unref_fn) (void *object, struct weak_ref_link **link);
|
||||
|
||||
struct lua_weak_info
|
||||
{
|
||||
const char *name; ///< Metatable name
|
||||
lua_weak_ref_fn ref; ///< Weak link invalidator
|
||||
lua_weak_unref_fn unref; ///< Weak link generator
|
||||
};
|
||||
|
||||
struct lua_weak
|
||||
{
|
||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||
struct user *user; ///< The user
|
||||
void *object; ///< The object
|
||||
struct weak_ref_link *weak_ref; ///< A weak reference link
|
||||
};
|
||||
|
||||
static void
|
||||
lua_user_invalidate (void *object, void *user_data)
|
||||
lua_weak_invalidate (void *object, void *user_data)
|
||||
{
|
||||
struct lua_user *wrapper = user_data;
|
||||
wrapper->user = NULL;
|
||||
struct lua_weak *wrapper = user_data;
|
||||
wrapper->object = NULL;
|
||||
wrapper->weak_ref = NULL;
|
||||
// This can in theory call the GC, order isn't arbitrary here
|
||||
lua_cache_invalidate (wrapper->plugin->L, object);
|
||||
}
|
||||
|
||||
static void
|
||||
lua_plugin_push_user (struct lua_plugin *plugin, struct user *user)
|
||||
lua_weak_push (struct lua_plugin *plugin, void *object,
|
||||
struct lua_weak_info *info)
|
||||
{
|
||||
lua_State *L = plugin->L;
|
||||
if (lua_cache_get (L, user))
|
||||
if (!object)
|
||||
{
|
||||
lua_pushnil (L);
|
||||
return;
|
||||
}
|
||||
if (lua_cache_get (L, object))
|
||||
return;
|
||||
|
||||
struct lua_user *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||
luaL_setmetatable (L, XLUA_USER_METATABLE);
|
||||
struct lua_weak *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||
luaL_setmetatable (L, info->name);
|
||||
wrapper->plugin = plugin;
|
||||
wrapper->user = user;
|
||||
wrapper->weak_ref = user_weak_ref (user, lua_user_invalidate, wrapper);
|
||||
lua_cache_store (L, user, -1);
|
||||
wrapper->object = object;
|
||||
wrapper->weak_ref = info->ref (object, lua_weak_invalidate, wrapper);
|
||||
lua_cache_store (L, object, -1);
|
||||
}
|
||||
|
||||
static int
|
||||
lua_weak_gc (lua_State *L, const struct lua_weak_info *info)
|
||||
{
|
||||
struct lua_weak *wrapper = luaL_checkudata (L, 1, info->name);
|
||||
if (wrapper->object)
|
||||
{
|
||||
lua_cache_invalidate (L, wrapper->object);
|
||||
info->unref (wrapper->object, &wrapper->weak_ref);
|
||||
wrapper->object = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lua_weak *
|
||||
lua_weak_deref (lua_State *L, const struct lua_weak_info *info)
|
||||
{
|
||||
struct lua_weak *weak = luaL_checkudata (L, 1, info->name);
|
||||
luaL_argcheck (L, weak->object, 1, "dead reference used");
|
||||
return weak;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/// Identifier for the Lua metatable
|
||||
#define XLUA_CHANNEL_METATABLE "channel"
|
||||
#define LUA_WEAK_DECLARE(id, metatable_id) \
|
||||
static struct lua_weak_info lua_ ## id ## _info = \
|
||||
{ \
|
||||
.name = metatable_id, \
|
||||
.ref = (lua_weak_ref_fn) id ## _weak_ref, \
|
||||
.unref = (lua_weak_unref_fn) id ## _weak_unref, \
|
||||
};
|
||||
|
||||
struct lua_channel
|
||||
{
|
||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||
struct channel *channel; ///< The channel
|
||||
struct weak_ref_link *weak_ref; ///< A weak reference link
|
||||
};
|
||||
#define XLUA_USER_METATABLE "user" ///< Identifier for Lua metatable
|
||||
#define XLUA_CHANNEL_METATABLE "channel" ///< Identifier for Lua metatable
|
||||
#define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for Lua metatable
|
||||
#define XLUA_SERVER_METATABLE "server" ///< Identifier for Lua metatable
|
||||
|
||||
static void
|
||||
lua_channel_invalidate (void *object, void *user_data)
|
||||
{
|
||||
struct lua_channel *wrapper = user_data;
|
||||
wrapper->channel = NULL;
|
||||
wrapper->weak_ref = NULL;
|
||||
// This can in theory call the GC, order isn't arbitrary here
|
||||
lua_cache_invalidate (wrapper->plugin->L, object);
|
||||
}
|
||||
|
||||
static void
|
||||
lua_plugin_push_channel (struct lua_plugin *plugin, struct channel *channel)
|
||||
{
|
||||
lua_State *L = plugin->L;
|
||||
if (lua_cache_get (L, channel))
|
||||
return;
|
||||
|
||||
struct lua_channel *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||
luaL_setmetatable (L, XLUA_CHANNEL_METATABLE);
|
||||
wrapper->plugin = plugin;
|
||||
wrapper->channel = channel;
|
||||
wrapper->weak_ref = channel_weak_ref
|
||||
(channel, lua_channel_invalidate, wrapper);
|
||||
lua_cache_store (L, channel, -1);
|
||||
}
|
||||
LUA_WEAK_DECLARE (user, XLUA_USER_METATABLE)
|
||||
LUA_WEAK_DECLARE (channel, XLUA_CHANNEL_METATABLE)
|
||||
LUA_WEAK_DECLARE (buffer, XLUA_BUFFER_METATABLE)
|
||||
LUA_WEAK_DECLARE (server, XLUA_SERVER_METATABLE)
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static int
|
||||
lua_user_gc (lua_State *L)
|
||||
{
|
||||
struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
|
||||
if (wrapper->user)
|
||||
{
|
||||
lua_cache_invalidate (L, wrapper->user);
|
||||
user_weak_unref (wrapper->user, &wrapper->weak_ref);
|
||||
wrapper->user = NULL;
|
||||
}
|
||||
return 0;
|
||||
return lua_weak_gc (L, &lua_user_info);
|
||||
}
|
||||
|
||||
static int
|
||||
lua_user_get_nickname (lua_State *L)
|
||||
{
|
||||
struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->user, 1, "dead reference used");
|
||||
lua_pushstring (L, wrapper->user->nickname);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
|
||||
struct user *user = wrapper->object;
|
||||
lua_pushstring (L, user->nickname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_user_get_channels (lua_State *L)
|
||||
{
|
||||
struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->user, 1, "dead reference used");
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
|
||||
struct user *user = wrapper->object;
|
||||
|
||||
int i = 1;
|
||||
lua_newtable (L);
|
||||
LIST_FOR_EACH (struct user_channel, iter, wrapper->user->channels)
|
||||
LIST_FOR_EACH (struct user_channel, iter, user->channels)
|
||||
{
|
||||
lua_plugin_push_channel (wrapper->plugin, iter->channel);
|
||||
lua_weak_push (wrapper->plugin, iter->channel, &lua_channel_info);
|
||||
lua_rawseti (L, -2, i++);
|
||||
}
|
||||
return 1;
|
||||
|
@ -8447,40 +8460,30 @@ static luaL_Reg lua_user_table[] =
|
|||
static int
|
||||
lua_channel_gc (lua_State *L)
|
||||
{
|
||||
struct lua_channel *wrapper =
|
||||
luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
|
||||
if (wrapper->channel)
|
||||
{
|
||||
lua_cache_invalidate (L, wrapper->channel);
|
||||
channel_weak_unref (wrapper->channel, &wrapper->weak_ref);
|
||||
wrapper->channel = NULL;
|
||||
}
|
||||
return 0;
|
||||
return lua_weak_gc (L, &lua_channel_info);
|
||||
}
|
||||
|
||||
static int
|
||||
lua_channel_get_name (lua_State *L)
|
||||
{
|
||||
struct lua_channel *wrapper =
|
||||
luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
|
||||
luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
|
||||
lua_pushstring (L, wrapper->channel->name);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
|
||||
struct channel *channel = wrapper->object;
|
||||
lua_pushstring (L, channel->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_channel_get_users (lua_State *L)
|
||||
{
|
||||
struct lua_channel *wrapper =
|
||||
luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
|
||||
luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
|
||||
struct channel *channel = wrapper->object;
|
||||
|
||||
int i = 1;
|
||||
lua_newtable (L);
|
||||
LIST_FOR_EACH (struct channel_user, iter, wrapper->channel->users)
|
||||
LIST_FOR_EACH (struct channel_user, iter, channel->users)
|
||||
{
|
||||
lua_createtable (L, 0, 2);
|
||||
lua_plugin_push_user (wrapper->plugin, iter->user);
|
||||
lua_weak_push (wrapper->plugin, iter->user, &lua_user_info);
|
||||
lua_setfield (L, -2, "user");
|
||||
lua_plugin_kv (L, "prefixes", iter->prefixes.str);
|
||||
|
||||
|
@ -8499,140 +8502,45 @@ static luaL_Reg lua_channel_table[] =
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for the Lua metatable
|
||||
|
||||
struct lua_buffer
|
||||
{
|
||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||
struct buffer *buffer; ///< The buffer
|
||||
struct weak_ref_link *weak_ref; ///< A weak reference link
|
||||
};
|
||||
|
||||
static void
|
||||
lua_buffer_invalidate (void *object, void *user_data)
|
||||
{
|
||||
struct lua_buffer *wrapper = user_data;
|
||||
wrapper->buffer = NULL;
|
||||
wrapper->weak_ref = NULL;
|
||||
// This can in theory call the GC, order isn't arbitrary here
|
||||
lua_cache_invalidate (wrapper->plugin->L, object);
|
||||
}
|
||||
|
||||
static void
|
||||
lua_plugin_push_buffer (struct lua_plugin *plugin, struct buffer *buffer)
|
||||
{
|
||||
lua_State *L = plugin->L;
|
||||
if (lua_cache_get (L, buffer))
|
||||
return;
|
||||
|
||||
struct lua_buffer *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||
luaL_setmetatable (L, XLUA_BUFFER_METATABLE);
|
||||
wrapper->plugin = plugin;
|
||||
wrapper->buffer = buffer;
|
||||
wrapper->weak_ref = buffer_weak_ref
|
||||
(buffer, lua_buffer_invalidate, wrapper);
|
||||
lua_cache_store (L, buffer, -1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#define XLUA_SERVER_METATABLE "server" ///< Identifier for the Lua metatable
|
||||
|
||||
struct lua_server
|
||||
{
|
||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||
struct server *server; ///< The server
|
||||
struct weak_ref_link *weak_ref; ///< A weak reference link
|
||||
};
|
||||
|
||||
static void
|
||||
lua_server_invalidate (void *object, void *user_data)
|
||||
{
|
||||
struct lua_server *wrapper = user_data;
|
||||
wrapper->server = NULL;
|
||||
wrapper->weak_ref = NULL;
|
||||
// This can in theory call the GC, order isn't arbitrary here
|
||||
lua_cache_invalidate (wrapper->plugin->L, object);
|
||||
}
|
||||
|
||||
static void
|
||||
lua_plugin_push_server (struct lua_plugin *plugin, struct server *server)
|
||||
{
|
||||
lua_State *L = plugin->L;
|
||||
if (lua_cache_get (L, server))
|
||||
return;
|
||||
|
||||
struct lua_server *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||
luaL_setmetatable (L, XLUA_SERVER_METATABLE);
|
||||
wrapper->plugin = plugin;
|
||||
wrapper->server = server;
|
||||
wrapper->weak_ref = server_weak_ref
|
||||
(server, lua_server_invalidate, wrapper);
|
||||
lua_cache_store (L, server, -1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static int
|
||||
lua_buffer_gc (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
if (wrapper->buffer)
|
||||
{
|
||||
lua_cache_invalidate (L, wrapper->buffer);
|
||||
buffer_weak_unref (wrapper->buffer, &wrapper->weak_ref);
|
||||
wrapper->buffer = NULL;
|
||||
}
|
||||
return 0;
|
||||
return lua_weak_gc (L, &lua_buffer_info);
|
||||
}
|
||||
|
||||
static int
|
||||
lua_buffer_get_user (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
|
||||
|
||||
if (wrapper->buffer->user)
|
||||
lua_plugin_push_user (wrapper->plugin, wrapper->buffer->user);
|
||||
else
|
||||
lua_pushnil (L);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
|
||||
struct buffer *buffer = wrapper->object;
|
||||
lua_weak_push (wrapper->plugin, buffer->user, &lua_user_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_buffer_get_channel (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
|
||||
|
||||
if (wrapper->buffer->channel)
|
||||
lua_plugin_push_channel (wrapper->plugin, wrapper->buffer->channel);
|
||||
else
|
||||
lua_pushnil (L);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
|
||||
struct buffer *buffer = wrapper->object;
|
||||
lua_weak_push (wrapper->plugin, buffer->channel, &lua_channel_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_buffer_get_server (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
|
||||
|
||||
if (wrapper->buffer->server)
|
||||
lua_plugin_push_server (wrapper->plugin, wrapper->buffer->server);
|
||||
else
|
||||
lua_pushnil (L);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
|
||||
struct buffer *buffer = wrapper->object;
|
||||
lua_weak_push (wrapper->plugin, buffer->server, &lua_server_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_buffer_log (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
|
||||
struct buffer *buffer = wrapper->object;
|
||||
const char *message = lua_plugin_check_utf8 (L, 2);
|
||||
|
||||
struct buffer *buffer = wrapper->buffer;
|
||||
log_full (wrapper->plugin->ctx, buffer->server, buffer,
|
||||
BUFFER_LINE_STATUS, "#s", message);
|
||||
return 0;
|
||||
|
@ -8641,11 +8549,9 @@ lua_buffer_log (lua_State *L)
|
|||
static int
|
||||
lua_buffer_execute (lua_State *L)
|
||||
{
|
||||
struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
|
||||
struct buffer *buffer = wrapper->object;
|
||||
const char *line = lua_plugin_check_utf8 (L, 2);
|
||||
|
||||
struct buffer *buffer = wrapper->buffer;
|
||||
process_input_utf8 (wrapper->plugin->ctx, buffer, line, 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -8667,50 +8573,33 @@ static luaL_Reg lua_buffer_table[] =
|
|||
static int
|
||||
lua_server_gc (lua_State *L)
|
||||
{
|
||||
struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
|
||||
if (wrapper->server)
|
||||
{
|
||||
lua_cache_invalidate (L, wrapper->server);
|
||||
server_weak_unref (wrapper->server, &wrapper->weak_ref);
|
||||
wrapper->server = NULL;
|
||||
}
|
||||
return 0;
|
||||
return lua_weak_gc (L, &lua_server_info);
|
||||
}
|
||||
|
||||
static int
|
||||
lua_server_get_user (lua_State *L)
|
||||
{
|
||||
struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->server, 1, "dead reference used");
|
||||
|
||||
if (wrapper->server->irc_user)
|
||||
lua_plugin_push_user (wrapper->plugin, wrapper->server->irc_user);
|
||||
else
|
||||
lua_pushnil (L);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
|
||||
struct server *server = wrapper->object;
|
||||
lua_weak_push (wrapper->plugin, server->irc_user, &lua_user_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_server_get_buffer (lua_State *L)
|
||||
{
|
||||
struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->server, 1, "dead reference used");
|
||||
|
||||
if (wrapper->server->buffer)
|
||||
lua_plugin_push_buffer (wrapper->plugin, wrapper->server->buffer);
|
||||
else
|
||||
lua_pushnil (L);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
|
||||
struct server *server = wrapper->object;
|
||||
lua_weak_push (wrapper->plugin, server->buffer, &lua_buffer_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lua_server_send (lua_State *L)
|
||||
{
|
||||
struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
|
||||
luaL_argcheck (L, wrapper->server, 1, "dead reference used");
|
||||
const char *line = luaL_checkstring (L, 2);
|
||||
|
||||
irc_send (wrapper->server, "%s", line);
|
||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
|
||||
struct server *server = wrapper->object;
|
||||
irc_send (server, "%s", luaL_checkstring (L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -8808,7 +8697,7 @@ lua_input_hook_filter (struct input_hook *self, struct buffer *buffer,
|
|||
|
||||
lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
|
||||
lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
|
||||
lua_plugin_push_buffer (plugin, buffer); // 2: buffer
|
||||
lua_weak_push (plugin, buffer, &lua_buffer_info); // 2: buffer
|
||||
lua_pushstring (L, input); // 3: input
|
||||
|
||||
struct error *e = NULL;
|
||||
|
@ -8839,7 +8728,7 @@ lua_irc_hook_filter (struct irc_hook *self, struct server *s, char *message)
|
|||
|
||||
lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
|
||||
lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
|
||||
lua_plugin_push_server (plugin, s); // 2: server
|
||||
lua_weak_push (plugin, s, &lua_server_info); // 2: server
|
||||
lua_pushstring (L, message); // 3: message
|
||||
|
||||
struct error *e = NULL;
|
||||
|
@ -8927,7 +8816,7 @@ lua_completion_hook_complete (struct completion_hook *self,
|
|||
lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
|
||||
lua_plugin_push_completion (L, data); // 2: data
|
||||
|
||||
lua_plugin_push_buffer (plugin, plugin->ctx->current_buffer);
|
||||
lua_weak_push (plugin, plugin->ctx->current_buffer, &lua_buffer_info);
|
||||
lua_setfield (L, -2, "buffer");
|
||||
|
||||
lua_pushstring (L, word); // 3: word
|
||||
|
|
Loading…
Reference in New Issue